OCCT + GTK4 not working

I tried to replicate this sample: https://github.com/gkv311/occt-samples-gtk/

While the original (which used GTK+-3.0) didn't start due to an old version of GTK+-3.0 being installed, my own implementation (using GTK4) did. However, I can't see anything on the blank GtkGlArea window, and I get:

TKOpenGl | Type: Other | ID: 0 | Severity: Medium | Message: OpenGl_Window::CreateWindow: window Visual is incomplete: no depth buffer, no stencil buffer

... despite having checked that gtk_gl_area_set_has_depth_buffer() and gtk_gl_area_set_has_stencil_buffer() are called. This is my code:


static void viewer_realize_callback(GtkWidget *self, gpointer user_data) { gtk_gl_area_make_current(GTK_GL_AREA(self)); int width = gtk_widget_get_width(self); int height = gtk_widget_get_height(self); int scale_factor = gtk_widget_get_scale_factor(self); gtk_gl_area_set_has_depth_buffer(GTK_GL_AREA(self), 1); gtk_gl_area_set_has_stencil_buffer(GTK_GL_AREA(self), 1); gtk_gl_area_attach_buffers(GTK_GL_AREA(self)); //gtk_gl_area_set_auto_render(GTK_GL_AREA(self), 0); EGLContext egl_context = eglGetCurrentContext(); if(egl_context != EGL_NO_CONTEXT) { EGLContext egl_display = eglGetCurrentDisplay(); EGLContext egl_surface = eglGetCurrentSurface(EGL_DRAW); EGLint egl_config_id = 0; EGLint num_configs = 0; eglQuerySurface(egl_display, egl_surface, EGL_CONFIG_ID, &egl_config_id); const EGLint config_attributes[] = {EGL_CONFIG_ID, egl_config_id, EGL_NONE}; void* egl_config = NULL; eglChooseConfig(egl_display, config_attributes, &egl_config, 1, &num_configs); run_at_viewer_realize( width, height, scale_factor, (void *) egl_context, (void *) egl_display, (void *) egl_config ); } else { GdkGLContext* gdk_gl_context = gdk_gl_context_get_current(); GdkDisplay* display = gdk_gl_context_get_display(gdk_gl_context); GdkSurface* surface = gdk_gl_context_get_surface(gdk_gl_context); Display *xdisplay = gdk_x11_display_get_xdisplay(display); Window gl_window = gdk_x11_surface_get_xid(surface); run_at_viewer_realize( width, height, scale_factor, (void *) NULL, (void *) xdisplay, (void *) gl_window ); } }

void backend_init_graphics(void) { display_connection = new Aspect_DisplayConnection(); viewer_driver = new OpenGl_GraphicDriver(display_connection, false); viewer_driver->ChangeOptions().buffersNoSwap = true; viewer_driver->ChangeOptions().buffersOpaqueAlpha = true; viewer_driver->ChangeOptions().useSystemBuffer = false; viewer = new V3d_Viewer(viewer_driver); viewer->SetDefaultBackgroundColor(Quantity_Color(Quantity_NOC_WHEAT)); viewer->SetDefaultLights(); viewer->SetLightOn(); viewer->ActivateGrid(Aspect_GT_Rectangular, Aspect_GDM_Lines); ais_context = new AIS_InteractiveContext(viewer); ais_controller = new AIS_ViewController(); view = viewer->CreateView(); view->SetImmediateUpdate(false); } void backend_realize_graphics( int width, int height, int scale_factor, void *context, void *display, void *config ) { Graphic3d_Vec2i logical_size(width, height); Graphic3d_Vec2i view_size = logical_size * scale_factor; opencascade::handle<OpenGl_Context> gl_context = new OpenGl_Context(); opencascade::handle<OcctGtkWindow> custom_window = dynamic_cast<OcctGtkWindow *>(view.get()); if(context != nullptr) { if(custom_window.get() == nullptr) { custom_window = new OcctGtkWindow(); } opencascade::handle<OpenGl_GraphicDriver> gl_driver = dynamic_cast<OpenGl_GraphicDriver *>( ais_context->CurrentViewer()->Driver().get() ) ; gl_driver->InitEglContext(display, context, config); custom_window->SetSize(view_size.x(), view_size.y()); custom_window->SetDevicePixelRatio(scale_factor); view->SetWindow(custom_window, gl_context->RenderingContext()); } else { opencascade::handle<OpenGl_GraphicDriver> gl_driver = dynamic_cast<OpenGl_GraphicDriver *>( ais_context->CurrentViewer()->Driver().get() ) ; //gl_driver.get()->GetDisplayConnection().get()->Init((Aspect_XDisplay *) display); //custom_window->SetNativeHandle((Aspect_Drawable) config); opencascade::handle<Xw_Window> xw_window = new Xw_Window(display_connection, (Aspect_Drawable) config); view->SetWindow(xw_window, gl_context->RenderingContext()); } // initPixelScaleRatio(); view->ChangeRenderingParams().Resolution = (unsigned int )(96.0 * scale_factor + 0.5); ais_context->SetPixelTolerance(int(scale_factor * 6.0)); /*TopoDS_Solid *undef_solid = new TopoDS_Solid(); opencascade::handle<AIS_Shape> interactive_shape = opencascade::handle<AIS_Shape>(new AIS_Shape(*undef_solid)); ais_context->Display(interactive_shape, 0);*/ }

Any ideas on what could be going wrong?

Kirill Gavrilov's picture

TKOpenGl | Type: Other | ID: 0 | Severity: Medium | Message:
OpenGl_Window::CreateWindow: window Visual is incomplete: no depth buffer, no stencil buffer

... despite having checked that gtk_gl_area_set_has_depth_buffer() and gtk_gl_area_set_has_stencil_buffer() are called. This is my code:

This is a warning message not an error. It usually doesn't lead to rendering issues.

Please use "Insert Code Snippet" (HTML editor) or ``` Markdown syntax while pasting code snippets - they are difficult to read.

aerkiaga's picture

Sorry, I wasn't aware I could use Markdown. The fact is, it doesn't work, and I'm not entirely sure why...

Kirill Gavrilov's picture

libgtk-4-dev isn’t available in Ubuntu 20.04 as far as I know. How did you installed it?

aerkiaga's picture

From source. Most of its dependencies are already there, so just a matter of compiling and installing. Same for OCCT (bc no debug symbols apparently).

Kirill Gavrilov's picture

Have you been able to build / run any GLArea samples using GTK4?

aerkiaga's picture

Haven't tried... Where can I get them? Are they bundled with the GTK4 sources?

aerkiaga's picture

Confirmed. All of the GTK4 demos build and run perfectly. Is there any way to build your code to run with gtkmm4? CMake only seems to accept gtkmm3... That way I'd be able to test! (well, it doesn't work with GTK+-3.0, because of the implementation bugs you mention, I assume).

Kirill Gavrilov's picture

Is there any way to build your code to run with gtkmm4? CMake only seems to accept gtkmm3...

You need to change gtkmm version in CMakeLists.txt and update sample based on changes in GTK API. Don't know if they have any dedicated upgrade guide describing these changes.

find_package (PkgConfig REQUIRED)
pkg_check_modules (GTKMM REQUIRED gtkmm-3.0)
aerkiaga's picture

Unfortunately I can't manage to build it on my system :(

I'm getting some interesting messages though, it looks like a GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT is being produced somewhere... Probably unrelated, but anyway.

aerkiaga's picture

This may be an old thread, but while looking at this I found a possible bug (as in, a concrete piece of code that appears to be wrong) in OpenGl_TextureFormat.hxx. I'll try a fix and see if this GTK4 issue gets fixed as well.

Basically, it's an instance where pixel formats like GL_RGBA are getting mixed up with internal formats like GL_RGBA8, which are constants defined with different numerical values.

Edit: OpenGl_TextureFormat.cxx has another instance of this, but I believe that one isn't the cause.

Răzvan Cosmin Rădulescu's picture

I ran into the same issue with gtkmm-4.0 so I started investigating a bit and there seems to be difference between v3.0 and v4.0 where gtkmm-4.0 doesn't fully prepare GLArea in the realize callback. Or I'm not sure how to put it in words.

Here's what I did:

  1. I got the official GLArea example from the GNOME repo and isolated it to test out some things.
  2. I removed the epoxy dependency and went back to "regular" libgl-dev (I use Linux). I'm using meson cause I find it easier than cmake, but I hope we can investigate together to figure out a solution so if there's anything anyone needs to collaborate on figuring out this stuff let me know... unless it's about Windows, I have no idea how to set stuff up on Windows.
  3. I checked the values of GLArea->get_width() & GLArea->get_height() and here's that I found that they're set to 0 in the realize callback. I would have expected them to have some size > 0 at this point. This is different from gtkmm-3.0.

I assume that somehow we're using the realize callback incorrectly, but I literally started programming gtkmm-4.0 and OpenCASCADE yesterday so I don't understand what's happening just yet.

I forked the occt-samples-gtk repo and made a branch with the example if anyone wants to check it out: https://github.com/razcore-rad/occt-gtk/tree/official-gtk. The file to look at is src/example_glarea.cpp. This branch is just the isolated gtkmm-4.0 example with no OpenCASCADE.

They also don't seem to have any OpenGL context initialization code in the example, I'm not sure how that ties in with OpenCASCADE OpenGl_Context::Init() function.


For meson you can compile and run with:

meson setup [--wipe] build
meson compile -C build
./build/occt-gtk

Where --wipe is like clear everything and start over. Only relevant after once running meson setup build, otherwise it gives an error.

Once meson setup build is ran, you can just do

meson compile -C build
./build/occt-gtk
Răzvan Cosmin Rădulescu's picture

This might be relevant: https://gitlab.gnome.org/GNOME/gtk/-/issues/4950. I did some more tests and with a sample code I found on stackoverflow I can confirm that gl-egl fails and I'm on NVidia as the user from the GNOME issue.

I have no idea what the implications would be with the OpenCASCADE Init()call though, because the stackoverflow test app runs fine without glewInit(). I haven't done any OpenGL development though so I don't understand what happens here.

occt-samples-gtk/stackoverflow_v4
❯ GDK_DEBUG=gl-glx build/app
on_realize() SIZE: 0x0
on_render()

occt-samples-gtk/stackoverflow_v4
❯ GDK_DEBUG=gl-egl build/app
on_realize() SIZE: 0x0
ERROR: Failed to initialize GLEW: Unknown error
on_render()

I also compiled some of the info I found on the issue on the GNOME forum.

That said, this seems to be unrelated with the size issue.

Răzvan Cosmin Rădulescu's picture

I had a chat with a GNOME developer in the Matrix chat and this is my conclusion:

  1. GtkGlArea size is 0 x 0 in the realize callback and this is correct since GTK4 follows Wayland which sets the size only on the first render.
  2. I haven't confirmed yet, but I'm pretty sure that EGL + GTK4 doesn't play well with NVidia and that's why initializing the context fails. A workaround is to build with GDK_DEBUG=gl-glx (probably).

With that I think we have a starting point.


For future reference I'm including the chat log from Matrix:

5/24/2023, 7:45:35 AM - Company: there's WGL for WIndows, Apple GL for Apple, GLX for X11 and EGL is the generic shiny new thing that is exclusively used by Wayland, but also has support for X (sometimes) and Windows
5/24/2023, 7:45:45 AM - razcore.rad: Even though I don't understand any of the code :)
5/24/2023, 7:45:53 AM - Company: GTK4 uses GL natively
5/24/2023, 7:46:17 AM - Company: so whenever you call any function, GL will already be initialized somehow
5/24/2023, 7:46:39 AM - Company: in GTK3 all those functions where probably called early enough for GtkGLArea not having initialized GL yet
5/24/2023, 7:47:10 AM - Company: GtkGLArea was the only thing using GL in GTK3
5/24/2023, 7:47:29 AM - razcore.rad: Right, I'll have to check the OpenCASCADE function to see if they do some funky stuff that is required in the init function or not, but I think I have the rough picture now, thanks a lot
5/24/2023, 7:48:05 AM - Company: if you use GSK_RENDERER=cairo, things might magiccally start working maybe
5/24/2023, 7:48:24 AM - Company: because that forces GTK to use Cairo and not GL
5/24/2023, 7:48:52 AM - razcore.rad: I don't think that works for what I want to do with OpenCASCADE, cause OpenCASCADE relies on GL
5/24/2023, 7:49:22 AM - Company: no, it's not a proper fix
5/24/2023, 7:49:28 AM - razcore.rad: Sure
5/24/2023, 7:49:50 AM - Company: but might work for confirming that's how things do indeed work (or fail)
5/24/2023, 7:51:46 AM - Company: you'll have to figure out how to best convince OpenCASCADE to use GTK's GL machinery
5/24/2023, 7:52:21 AM - Company: because it needs a GL context, but it seems to want to create its own one
5/24/2023, 7:52:30 AM - Company: using some platform library
5/24/2023, 7:52:53 AM - Company: it would be easiest if you could convince it to wrap a GdkGLContext instead
5/24/2023, 7:53:06 AM - razcore.rad: Yep, I'll look into it
5/24/2023, 7:53:24 AM - Company: if you can't, you'll need to write code to detect which platform library GTK uses and then figure out how to extract the right information for it and pass it on
5/24/2023, 7:54:30 AM - razcore.rad: For those curious this is the relevant OpenCASCADE-GTK3 sample demo part https://github.com/gkv311/occt-samples-gtk/blob/23a802cd619c50678e18ed57e6c69830bb5ae1af/OcctGtkViewer.cxx#LL386C39-L386C39
5/24/2023, 7:54:35 AM - Company: which is a mess, but it's what happens with GStreamer - see https://gitlab.gnome.org/GNOME/gtk/-/blob/main/modules/media/gtkgstsink.c#L382-534 if you want to read 150 lines of messy code
5/24/2023, 7:54:53 AM - eyeris left the room: Quit: Quit: leaving
5/24/2023, 7:55:13 AM - razcore.rad: I might just switch to QT since all their OpenCASCADE are in QT anyway, or just stick with GTK3 we'll see :)
5/24/2023, 7:56:16 AM - Company: that code is not gonna work
5/24/2023, 7:56:26 AM - Company: it's trying to wrap a whole native surface
5/24/2023, 7:56:38 AM - razcore.rad: I figured that part out
5/24/2023, 7:57:28 AM - Company: and if you do that, you (a) will overdraw the whole window, not just the GL Area and (b) GTK uses GL on that surface, so opencascade and GTK will fight over it and most likely a crash will win that fight
5/24/2023, 7:58:24 AM - Company: it's only gonna work if you can make it drop to offscreen framebuffers
5/24/2023, 7:58:29 AM - Company: *Draw to
5/24/2023, 7:58:40 AM - razcore.rad: I think that's what the sample app does
5/24/2023, 7:59:57 AM - razcore.rad: It's explained here https://unlimited3d.wordpress.com/2021/07/29/occt-viewer-and-gtk/ at `Wrapping existing FBO`
5/24/2023, 8:02:33 AM - Company: right
5/24/2023, 8:02:53 AM - Company: that requires figuring out how to pass the fbo and GL context properly down to it
5/24/2023, 8:03:13 AM - Company: you just need to ignore all the other ways listed there where native windows are handed over
5/24/2023, 8:04:29 AM - Company: i'm off to bed now
5/24/2023, 8:04:34 AM - razcore.rad: Yea, I think I'm on the right track here, I'll dig some more into it. Right I'm pretty certain that one problem is that EGL bug with NVidia, but I don't care about it for now
5/24/2023, 8:04:35 AM - razcore.rad: Thanks
5/24/2023, 8:04:37 AM - Company: good luck digging through that mess
5/24/2023, 8:04:53 AM - razcore.rad: :)
5/24/2023, 8:05:27 AM - Company left the room: Quit: Quit: Leaving