wayland
FreeBodyEngine.graphics.gl33.context.wayland
#
Wayland equivalent of create_win32_opengl_context, using EGL instead of WGL (Wayland has no WGL/GLX-style "get a DC and pick a pixel format" API - EGL is the only game in town).
Unlike WGL, EGL doesn't work directly against a wl_surface - Wayland has no
native concept of a drawable surface for GL to render into. You have to wrap
the wl_surface in a wl_egl_window (from libwayland-egl) first, and that's
that which gets handed to eglCreateWindowSurface. This module does that
wrapping via ctypes, since PyOpenGL doesn't bind libwayland-egl itself.
Expects window to be a WaylandWindow (see window_wayland.py) - specifically
it needs window.native_display (wl_display) and window.native_surface
(wl_surface).
Because there's no separate "hdc" object to hang the swap-chain off of like there is on Win32, this stores everything EGL-related it created directly on the window object:
window.egl_display - EGLDisplay
window.egl_surface - EGLSurface (the thing you eglSwapBuffers)
window.egl_context - EGLContext (also returned, for parity with the
win32 version returning `hrc`)
window._egl_window - the underlying wl_egl_window*, needed if you ever
call wl_egl_window_resize on a resize event
Dependencies: PyOpenGL (for OpenGL.EGL) and libwayland-egl.so (comes with the wayland client libraries most distros already have installed - it's what any Wayland+EGL app, Qt/GTK/SDL included, links against).
EGL_CONTEXT_MAJOR_VERSION = 12440
module-attribute
#
EGL_CONTEXT_MINOR_VERSION = 12539
module-attribute
#
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT = 1
module-attribute
#
EGL_CONTEXT_OPENGL_DEBUG = 12720
module-attribute
#
EGL_CONTEXT_OPENGL_PROFILE_MASK = 12541
module-attribute
#
create_wayland_opengl_context(window, debug)
#
Sets up a GL 3.3 core-profile context for window via EGL: gets and
initializes the EGL display for window.native_display, binds the
OpenGL API, chooses an EGLConfig matching an RGBA8/24-depth/8-stencil
pixel format, wraps window.native_surface in a wl_egl_window (the
native-window handle EGL actually needs - Wayland itself has no drawable
surface concept GL can render into directly, see the module docstring),
creates the EGL surface and context (requesting the debug context bit if
debug is set), and makes it all current. Every object created is
stashed directly onto window (egl_display/egl_surface/
egl_context/_egl_window) since there's no single handle like Win32's
hdc to carry it on; returns egl_context for parity with
create_win32_opengl_context's hrc return.
destroy_wayland_opengl_context(window)
#
Tears down everything create_wayland_opengl_context() set up, in
reverse: unbinds the context (eglMakeCurrent with no surface/context),
destroys the EGL context and surface, destroys the underlying
wl_egl_window wrapper (via libwayland-egl), and terminates the EGL
display connection.
resize_wayland_opengl_surface(window, width, height)
#
Call this from the window's resize handler - but note it doesn't resize anything immediately. It just queues the resize; the actual wl_egl_window_resize call happens in swap_wayland_opengl_buffers, right after the next eglSwapBuffers.
This split matters: Wayland-EGL forbids issuing draw calls in between SwapBuffers and wl_egl_window_resize. Calling wl_egl_window_resize straight from an event callback (which can land at any point relative to your frame - mid-draw, pre-swap, whenever) is a known cause of resizes silently doing nothing or the surface hanging/getting stuck at the old size, especially on wlroots-based compositors (Hyprland, Sway) and nVidia's EGLStreams implementation. SDL hit exactly this and fixed it the same way: apply the new size only right after a swap.
swap_wayland_opengl_buffers(window)
#
Equivalent of Win32's SwapBuffers(hdc); call this from window.draw().
Plain and unconditional. Two attempts at skipping this call while the surface isn't actually visible (switched away to another workspace, minimized, occluded) - to stop it blocking on presentation feedback that wouldn't arrive until it became visible again, which is the root cause of this app occasionally getting flagged "not responding" - were each tried and reverted: skipping it directly based on the xdg_toplevel "suspended" state (an optional v6+ addition no compositor is guaranteed to actually deliver), then gating it on a wl_surface.frame() "done" callback instead (reproduced a worse, near-immediate freeze even while fully visible - almost certainly fighting Mesa's own internal EGL presentation-feedback pacing on this same surface, which neither attempt touched). See WaylandWindow._on_toplevel_configure for the "suspended" tracking that's still there but unused. The underlying freeze is real and still unfixed as of this revert.