In my viewer, I create thumbnails on a separate thread, by creating a
class that inherits from Fl_Gl_Window but it is never shown. I'll show
the code I have for X11 (which works) and the one for Wayland (which
doesn't).
My first issue is that fl_wl_xid(this) returns nullptr, at least until
the window is shown. This is different that what happens with macOS,
X11 or Windows.
I cannot show the window in the separate thread.
Le jeudi 8 décembre 2022 à 22:55:12 UTC+1, ggar...@gmail.com a écrit :
In my viewer, I create thumbnails on a separate thread, by creating a
class that inherits from Fl_Gl_Window but it is never shown. I'll show
the code I have for X11 (which works) and the one for Wayland (which
doesn't).
My first issue is that fl_wl_xid(this) returns nullptr, at least until
the window is shown. This is different that what happens with macOS,
X11 or Windows.
That's wrong.fl_xid() and its new variants fl_wl_xid(), fl_x11_xid(), … return NULL before the window is shownand non-nul after.
You are right. On X11 however, I can have:
glXMakeCurrent(fl_x11_display(), fl_x11_xid(this), ctx);
with a null fl_x11_xid and OpenGL3 multithreading will work. On
macOS I can create a context without any window.
I cannot show the window in the separate thread.Do you mean that you create the GL3 window in a child thread and then show itin the main thread?Why don't make both in the main thread?
No, the window creation happens in the main thread but the window is never shown (mapped). I create a new OpenGL context in the worker thread, so OpenGL will work on that thread. The OpenGL3 drawing happens on this separate thread to create a thumbnail, not on the draw() function.
Once the thumbnail is rendered into a Fl_RGB_Image, it is
returned to the main thread to use as it wants.
I have code for macOS, Windows and X11 works. I now have also code for Wayland that works, but it needs the GL window to be shown first on the main thread, as I need to do:
wld_window* win = fl_wl_xid(this);
wl_surface* surface = fl_wl_surface(win);
I would like to obtain a wl_surface() without showing the window.
I see you duplicate wayland-specific code here that is already in the FLTK library.Why?
Because the GL context needs to be created in the worker thread
to work with OpenGL multithreaded. I cannot just call
make_current() on the worker thread without a crash. Sadly, FLTK
does not expose the Wayland's egl internal pointers and config.
If it did I could reduce the code to just two calls, like on X11
(creating the GL context and making it current).
That's why I need to do all this (this is tested and works):
wl_display* wld = fl_wl_display();
if ( wld )
{
wld_window* win = fl_wl_xid(this); // this works of course if I show the window on the main thread
if ( !win )
{
std::cerr << "No window" <<
std::endl;
return;
}
surface = fl_wl_surface(win);
if ( !surface )
{
std::cerr << "No surface" <<
std::endl;
return;
}
egl_display = eglGetDisplay((EGLNativeDisplayType)
wld);
if (egl_display == EGL_NO_DISPLAY) {
std::cerr << "Can't create egl display"
<< std::endl;
return;
}
egl_window = wl_egl_window_create(surface, pixel_w(),
pixel_h() );
if ( egl_window == EGL_NO_SURFACE )
{
std::cerr << "Could not create egl window"
<< std::endl;
return;
}
// Wayland specific code here
EGLint numConfigs;
EGLint major, minor;
EGLConfig config;
EGLint fbAttribs[] =
{
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 0,
EGL_SAMPLE_BUFFERS, 0,
EGL_STENCIL_SIZE, 0,
EGL_NONE
};
EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE, EGL_NONE };
if (eglInitialize(egl_display, &major,
&minor) != EGL_TRUE) {
std::cerr << "Can't initialise egl
display" << std::endl;
return;
}
if ( (eglGetConfigs(egl_display, NULL, 0,
&numConfigs) !=
EGL_TRUE) || (numConfigs == 0))
{
std::cerr << "No Configuration..."
<< std::endl;
return;
}
eglBindAPI(EGL_OPENGL_API);
if ( (eglChooseConfig(egl_display, fbAttribs,
&config, 1,
&numConfigs) != EGL_TRUE)
||
(numConfigs != 1))
{
std::cerr << "No Chosen Configuration..."
<< std::endl;
return;
}
egl_surface = eglCreateWindowSurface(egl_display,
config,
egl_window,
NULL);
if ( !egl_surface )
{
std::cerr << "Could not create egl
surface" << std::endl;
return;
}
auto ctx = eglCreateContext( egl_display, config,
EGL_NO_CONTEXT,
contextAttribs );
if ( ctx == EGL_NO_CONTEXT )
{
std::cerr << "No context...\n" <<
std::endl;
return;
}
if ( ! eglMakeCurrent( egl_display, egl_surface,
egl_surface, ctx ) )
{
std::cerr << "Could not make the current
window current"
<< std::endl;
return;
}
}
and at the end of the thread:
#if defined(FLTK_USE_WAYLAND)
if ( wld )
{
eglDestroySurface( egl_display, egl_surface );
wl_egl_window_destroy( egl_window );
}
#endif
El 9/12/22 a las 03:25, Manolo escribió:
I have code for macOS, Windows and X11 works. I now have also code for Wayland that works, but it needs the GL window to be shown first on the main thread, as I need to do:
wld_window* win = fl_wl_xid(this);
wl_surface* surface = fl_wl_surface(win);I would like to obtain a wl_surface() without showing the window.
I see you duplicate wayland-specific code here that is already in the FLTK library.Why?
Because the GL context needs to be created in the worker thread to work with OpenGL multithreaded. I cannot just call make_current() on the worker thread without a crash. Sadly, FLTK does not expose the Wayland's egl internal pointers and config. If it did I could reduce the code to just two calls, like on X11 (creating the GL context and making it current).
That's why I need to do all this (this is tested and works):
………
I agree with the public FLTK API, it's not possible to get a wl_surface without showing the corresponding window.
You may proceed as follows , though, accessing internal, Wayland-specific data structures :#include "src/drivers/Wayland/Fl_Wayland_Screen_Driver.H" // requires an adequate -I at compile timeFl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();struct wl_surface *my_wl_surface = wl_compositor_create_surface(scr_driver->wl_compositor);to create a wl_surface without Fl_Window. I don't guarantee that this wl_surface is usable, though.
Excellent! That worked perfectly. You may want to create a public function in FL/wayland.H to create a surface so that I don't need to point the include to the src/ directory.
wl_surface* fl_wl_create_surface();
Or better yet, you might want to return the current compositor, like:
wl_compositor* fl_wl_compositor();