Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenGL3 Backend: VAO is disabled for emscripten/wasm build #4266

Closed
harry75369 opened this issue Jun 25, 2021 · 8 comments
Closed

OpenGL3 Backend: VAO is disabled for emscripten/wasm build #4266

harry75369 opened this issue Jun 25, 2021 · 8 comments

Comments

@harry75369
Copy link
Contributor

Version/Branch of Dear ImGui:

Dear ImGui 1.83 (18300)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=201703
define: __linux__
define: __GNUC__=11
--------------------------------
io.BackendPlatformName: imgui_impl_sdl
io.BackendRendererName: imgui_impl_opengl3
io.ConfigFlags: 0x00000020
 NoMouseCursorChange
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x0000000E
 HasMouseCursors
 HasSetMousePos
 RendererHasVtxOffset
--------------------------------
io.Fonts: 2 fonts, Flags: 0x00000000, TexSize: 1024,2048
io.DisplaySize: 1200.00,800.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------
style.WindowPadding: 8.00,8.00
style.WindowBorderSize: 1.00
style.FramePadding: 4.00,3.00
style.FrameRounding: 0.00
style.FrameBorderSize: 0.00
style.ItemSpacing: 8.00,4.00
style.ItemInnerSpacing: 4.00,4.00

My Issue/Question:
In OpenGL3 backend, VAO is disabled for ES2, using macros like this:

#ifndef IMGUI_IMPL_OPENGL_ES2
glBindVertexArray(vertex_array_object);
#endif

VAO is not available in OpenGL ES2 standard, so this is correct.

For emscripten/wasm build, ImGui assume WebGL 1 (which derived from ES2), rather than WebGL 2 (which derived from ES3) , so disabling VAO for WebGL 1 seems also correct.

However, there is OES_vertex_array_object extension for OpenGL ES2 and WebGL 1, which is widely and well supported in most browsers (https://caniuse.com/mdn-api_oes_vertex_array_object).

Lacking VAO support in ImGui wasm build (WebGL 1) is not a good thing. It will conflicts with other graphics libraries badly, causing weird rendering bugs.

This problem bothers me for several days until VAO is fixed. Hope others may find this helpful.

Screenshots/Video:
Standalone, minimal, complete and verifiable example:

Sorry but no screenshots nor code example could be provided due to license issue. I think the problem is already clearly stated above. And patches will be provided later.

@ocornut
Copy link
Owner

ocornut commented Jun 25, 2021

Hello,

Lacking VAO support in ImGui wasm build (WebGL 1) is not a good thing. It will conflicts with other graphics libraries badly, causing weird rendering bugs.

Can you clarify that? How does NOT using those functions create a problem?
Can you clarify the benefits of using them there?

@harry75369
Copy link
Contributor Author

I created a test app for clarifying rendering bugs with other graphics lib, specifically, skia lib. The test app is created using the following code snippets

  virtual void onFrame() override                                                                                                                                                                                                                                                           
  {                                                                                                                                                                                                                                                                                         
    auto canvas = getCanvas();                                                                                                                                                                                                                                                              
    ASSERT(canvas);                                                                                                                                                                                                                                                                         
    canvas->drawColor(SK_ColorGREEN);                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                            
    auto fp = FramedPath{                                                                                                                                                                                                                                                                   
      .frame = Frame{ 0, 0, 200, 200 },                                                                                                                                                                                                                                                     
      .path = RectPath::create(),                                                                                                                                                                                                                                                           
    };                                                                                                                                                                                                                                                                                      
    auto skPath = GeometrySystem::getSkiaPath(fp);                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                                                                            
    SkPaint paint;                                                                                                                                                                                                                                                                          
    paint.setAntiAlias(true);                                                                                                                                                                                                                                                               
    paint.setColor(SK_ColorYELLOW);                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                            
    canvas->save();                                                                                                                                                                                                                                                                         
    canvas->translate(100, 100);                                                                                                                                                                                                                                                            
    canvas->drawPath(skPath, paint);                                                                                                                                                                                                                                                        
    paint.setStyle(SkPaint::kStroke_Style);                                                                                                                                                                                                                                                 
    paint.setColor(SK_ColorRED);                                                                                                                                                                                                                                                            
    paint.setStrokeWidth(1);
    canvas->drawPath(skPath, paint);
    canvas->restore();
  }

  virtual void onImGuiFrame() override
  {
    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplSDL2_NewFrame(m_sdlState.window);
    ImGui::NewFrame();

    if (ImGui::BeginMainMenuBar())
    {
      if (ImGui::MenuItem("Toggle Window"))
      {
        m_showImGuiWindow = !m_showImGuiWindow;
      }
      ImGui::EndMainMenuBar();
    }
    if (m_showImGuiWindow)
    {
      ImGui::SetNextWindowPos(ImVec2(100 * DPI::ScaleFactor, 100 * DPI::ScaleFactor),
                              ImGuiCond_Appearing);
      ImGui::SetNextWindowSize(ImVec2(200 * DPI::ScaleFactor, 200 * DPI::ScaleFactor),
                               ImGuiCond_Appearing);
      if (ImGui::Begin("Window", &m_showImGuiWindow, ImGuiWindowFlags_NoNav))
      {
      }
      ImGui::End();
    }

    ImGui::Render();
    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
  }

In each frame, onFrame will be invoked first, then onImGuiFrame. And the video recordings are as follows:

With VAO disabled, OpenGL ES2

Peek 2021-06-25 18-35

[INFO] SDL version 2.0.14 (linked 2.0.14)
[INFO] GL_VENDOR: AMD
[INFO] GL_RENDERER: Radeon RX 560 Series (POLARIS11, DRM 3.40.0, 5.10.42-1-MANJARO, LLVM 12.0.0)
[INFO] GL_VERSION: OpenGL ES 3.2 Mesa 21.1.2
[INFO] GL_SHADING_LANGUAGE_VERSION: OpenGL ES GLSL ES 3.20

(Note SDL is requesting OpenGL ES2 but received ES3 context, however, imgui is built with IMGUI_IMPL_OPENGL_ES2)
Problems:

  • skia: no red stroke
  • imgui: window not transparent; appearing and disappearing extra border under main menu and at top of the window

With VAO disabled, WebGL 1

Peek 2021-06-25 18-24

[INFO] SDL version 2.0.10 (linked 2.0.10)
[INFO] GL_VENDOR: Mozilla
[INFO] GL_RENDERER: Mozilla
[INFO] GL_VERSION: OpenGL ES 2.0 (WebGL 1.0)
[INFO] GL_SHADING_LANGUAGE_VERSION: OpenGL ES GLSL ES 1.00 (WebGL GLSL ES 1.0)

Problems:

  • skia: no red stroke
  • imgui: window is transparent, but has weird opaque shadow

With VAO enabled, OpenGL ES2

Peek 2021-06-25 18-49

[INFO] SDL version 2.0.14 (linked 2.0.14)
[INFO] GL_VENDOR: AMD
[INFO] GL_RENDERER: Radeon RX 560 Series (POLARIS11, DRM 3.40.0, 5.10.42-1-MANJARO, LLVM 12.0.0)
[INFO] GL_VERSION: OpenGL ES 3.2 Mesa 21.1.2
[INFO] GL_SHADING_LANGUAGE_VERSION: OpenGL ES GLSL ES 3.20

(Note SDL is requesting OpenGL ES2 but received ES3 context, and imgui is built without IMGUI_IMPL_OPENGL_ES2)
Everything is fine.

With VAO enabled, WebGL 1

Peek 2021-06-25 18-55

[INFO] SDL version 2.0.10 (linked 2.0.10)
[INFO] GL_VENDOR: Mozilla
[INFO] GL_RENDERER: Mozilla
[INFO] GL_VERSION: OpenGL ES 2.0 (WebGL 1.0)
[INFO] GL_SHADING_LANGUAGE_VERSION: OpenGL ES GLSL ES 1.00 (WebGL GLSL ES 1.0)

Everything is fine.

Conclusion

This problem only appears in OpenGL ES2 and WebGL 1, since other opengl versions supports VAO natively, including WebGL 2. Using OES_vertex_array_object helps solve those problems for OpenGL ES2 and WebGL 1.

And this test app only shows part of rendering bugs. In real application, the rendering is more severe, for example, flickering, mysterious triangles and etc.

@harry75369
Copy link
Contributor Author

And please note my patches only enable VAO for WebGL 1, not for ES2 yet.

@ocornut
Copy link
Owner

ocornut commented Jun 25, 2021

What happens if instead of the patch you call glBindVertexArrayOES(0) in your code before calling ImGui_ImplOpenGL3_RenderDrawData() ?

@ocornut
Copy link
Owner

ocornut commented Jun 25, 2021

Thanks for the all the details above.
Could you rework your PR using:

// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
#ifndef IMGUI_IMPL_OPENGL_ES2
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
#elif defined(__EMSCRIPTEN__)
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
#define glBindVertexArray       glBindVertexArrayOES
#define glGenVertexArrays       glGenVertexArraysOES
#define glDeleteVertexArrays    glDeleteVertexArraysOES
#define
#endif
  • using GL_VERTEX_ARRAY_BINDING everywhere (instead of GL_VERTEX_ARRAY_BINDING_OES, same value)
  • using #ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY everywhere with a single block

This way the code will be simplier.

Thank you!

@harry75369
Copy link
Contributor Author

What happens if instead of the patch you call glBindVertexArrayOES(0) in your code before calling ImGui_ImplOpenGL3_RenderDrawData() ?

Tried, but to no avail.

@harry75369
Copy link
Contributor Author

harry75369 commented Jun 25, 2021

PR updated. Maybe you are missing redefining GL_VERTEX_ARRAY_BINDING.

// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
#ifndef IMGUI_IMPL_OPENGL_ES2
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
#elif defined(__EMSCRIPTEN__)
#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
#define glBindVertexArray       glBindVertexArrayOES
#define glGenVertexArrays       glGenVertexArraysOES
#define glDeleteVertexArrays    glDeleteVertexArraysOES
#define
#endif
* using `GL_VERTEX_ARRAY_BINDING` everywhere (instead of `GL_VERTEX_ARRAY_BINDING_OES`, same value)

This is not possible without redefining GL_VERTEX_ARRAY_BINDING as GL_VERTEX_ARRAY_BINDING_OES, since GL_VERTEX_ARRAY_BINDING is not defined in GLES2/gl2.h

cat /usr/include/GLES2/gl2.h | grep GL_VERTEX_ARRAY_BINDING # returns nothing

@ocornut
Copy link
Owner

ocornut commented Jun 25, 2021

Merged! Thank you very much for the careful work and followup!

@ocornut ocornut closed this as completed Jun 25, 2021
@ocornut ocornut added the web label Jul 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants