diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-13 23:52:22 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-13 23:52:22 +0300 |
| commit | 563b23a33726289387193b85d90fb569631ee05f (patch) | |
| tree | ddf438338034b5ab2690b531684906999e56df44 /src/platform/wayland/backend.c | |
| parent | 76073fe5fad8799e5850805f2f090af2cb62c741 (diff) | |
Reconnect to a restarted Wayland compositor
Windows now outlive the compositor. On connection loss YASL sends
DISPLAY_LOST instead of closing every window, retries the connection on
a loop timer, rebuilds each toplevel with its title, size, state and GL
context, and sends DISPLAY_RESTORED. CPU windows keep their pixels;
GPU renderers drop Vulkan surfaces and GL objects on loss and rebuild
them on restore.
- Free the dead connection's objects on the next wait, after the
application has released GPU objects built on them.
- Report a lost connection as an event rather than a failed wait.
- Refuse window and Vulkan surface creation while offline with the new
YASL_ERROR_DISCONNECTED.
- Close popups, cancel drags and fail pending clipboard requests on loss.
- Print only protocol errors, not ordinary disconnects.
- Examples survive a restart; game.c rebinds its GL context.
- Add an end-to-end test that kills Weston under CPU, GL and Vulkan
windows and requires them to recover.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'src/platform/wayland/backend.c')
| -rw-r--r-- | src/platform/wayland/backend.c | 82 |
1 files changed, 49 insertions, 33 deletions
diff --git a/src/platform/wayland/backend.c b/src/platform/wayland/backend.c index 02aae59..b3337cc 100644 --- a/src/platform/wayland/backend.c +++ b/src/platform/wayland/backend.c @@ -125,42 +125,36 @@ static bool egl_configure(struct wayland_display *d, const struct yasl_private_g return eglBindAPI(api) == EGL_TRUE; } -static struct yasl_surface *impl_surface_create_gl(struct yasl_private_display *display, - const struct yasl_private_window_spec *spec, const int *attributes, struct yasl_surface *share) -{ - struct wayland_display *d = (struct wayland_display *)display; - struct yasl_private_gl_options o; - if (!spec || !yasl_private_gl_parse_options(attributes, &o) || !d || !d->egl_initialized) - return NULL; - struct yasl_private_window_spec gl_spec = *spec; - gl_spec.external_gpu = true; - gl_spec.flags &= ~YASL_PRIVATE_SURFACE_CPU; - struct wayland_surface *w = wayland_surface_create_toplevel(d, &gl_spec, NULL); - if (!w) return NULL; - if (!egl_configure(d, &o, &w->egl_config)) goto fail; - EGLContext share_context = share && share->display == display - ? ((struct wayland_surface *)share)->egl_context : EGL_NO_CONTEXT; - if (share && share_context == EGL_NO_CONTEXT) goto fail; +bool surface_build_gl(struct wayland_surface *w) +{ + struct wayland_display *d = w->conn; + const struct yasl_private_gl_options *o = &w->gl_options; + if (!egl_configure(d, o, &w->egl_config)) return false; + EGLContext share_context = EGL_NO_CONTEXT; + if (w->gl_share) { + if (!w->gl_share->gl_built && !surface_build_gl(w->gl_share)) return false; + share_context = w->gl_share->egl_context; + } w->egl_window = wl_egl_window_create(w->surface, w->width, w->height); - if (!w->egl_window) goto fail; + if (!w->egl_window) return false; EGLint context_attrs[12]; int n = 0; - if (o.api == YASL_PRIVATE_GL_OPENGL_ES) { + if (o->api == YASL_PRIVATE_GL_OPENGL_ES) { context_attrs[n++] = EGL_CONTEXT_CLIENT_VERSION; - context_attrs[n++] = o.major; + context_attrs[n++] = o->major; } else { context_attrs[n++] = EGL_CONTEXT_MAJOR_VERSION_KHR; - context_attrs[n++] = o.major; + context_attrs[n++] = o->major; context_attrs[n++] = EGL_CONTEXT_MINOR_VERSION_KHR; - context_attrs[n++] = o.minor; - if (o.profile != YASL_PRIVATE_GL_ANY) { + context_attrs[n++] = o->minor; + if (o->profile != YASL_PRIVATE_GL_ANY) { context_attrs[n++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; - context_attrs[n++] = o.profile == YASL_PRIVATE_GL_CORE + context_attrs[n++] = o->profile == YASL_PRIVATE_GL_CORE ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; } - EGLint flags = (o.debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0) | - (o.forward_compat ? EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR : 0); + EGLint flags = (o->debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0) | + (o->forward_compat ? EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR : 0); if (flags) { context_attrs[n++] = EGL_CONTEXT_FLAGS_KHR; context_attrs[n++] = flags; @@ -168,21 +162,42 @@ static struct yasl_surface *impl_surface_create_gl(struct yasl_private_display * } context_attrs[n] = EGL_NONE; w->egl_context = eglCreateContext(d->egl_display, w->egl_config, share_context, context_attrs); - if (w->egl_context == EGL_NO_CONTEXT) goto fail; + if (w->egl_context == EGL_NO_CONTEXT) { w->egl_context = 0; return false; } EGLint surface_attrs[] = { #ifdef EGL_GL_COLORSPACE_KHR - EGL_GL_COLORSPACE_KHR, o.srgb ? EGL_GL_COLORSPACE_SRGB_KHR : EGL_GL_COLORSPACE_LINEAR_KHR, + EGL_GL_COLORSPACE_KHR, o->srgb ? EGL_GL_COLORSPACE_SRGB_KHR : EGL_GL_COLORSPACE_LINEAR_KHR, #endif EGL_NONE, }; w->egl_surface = eglCreateWindowSurface(d->egl_display, w->egl_config, (EGLNativeWindowType)w->egl_window, surface_attrs); - if (w->egl_surface == EGL_NO_SURFACE) { w->egl_surface = 0; goto fail; } + if (w->egl_surface == EGL_NO_SURFACE) { w->egl_surface = 0; return false; } + w->gl_built = true; + return true; +} + +static struct yasl_surface *impl_surface_create_gl(struct yasl_private_display *display, + const struct yasl_private_window_spec *spec, const int *attributes, struct yasl_surface *share) +{ + struct wayland_display *d = (struct wayland_display *)display; + struct yasl_private_gl_options o; + if (!spec || !yasl_private_gl_parse_options(attributes, &o) || !d || !d->egl_initialized) + return NULL; + if (share && (share->display != display || !((struct wayland_surface *)share)->egl_context)) + return NULL; + struct yasl_private_window_spec gl_spec = *spec; + gl_spec.external_gpu = true; + gl_spec.flags &= ~YASL_PRIVATE_SURFACE_CPU; + struct wayland_surface *w = wayland_surface_create_toplevel(d, &gl_spec, NULL); + if (!w) return NULL; + w->gl_options = o; + w->gl_share = (struct wayland_surface *)share; + if (!surface_build_gl(w)) { + wayland_surface_destroy(w); + return NULL; + } w->base.presenter = YASL_PRIVATE_PRESENTER_GL; return &w->base; -fail: - wayland_surface_destroy(w); - return NULL; } static bool impl_gl_make_current(struct yasl_private_display *display, struct yasl_surface *surface) @@ -250,7 +265,7 @@ static struct input_queue *impl_surface_input_queue(struct yasl_surface *s) static bool impl_surface_set_size(struct yasl_surface *s, struct yasl_private_vector2i size) { struct wayland_surface *w = (struct wayland_surface *)s; - if (!w || w->closed || w->destroyed || !w->toplevel || + if (!w || w->closed || w->destroyed || (!w->toplevel && !w->conn->lost) || size.x <= 0 || size.y <= 0) { errno = EINVAL; return false; @@ -258,7 +273,8 @@ static bool impl_surface_set_size(struct yasl_surface *s, struct yasl_private_ve /* Floating windows choose their own size; constrained states keep it for later. */ w->floating_width = size.x; w->floating_height = size.y; - if (w->base.state & (YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_TILED)) + if (w->conn->lost || + (w->base.state & (YASL_PRIVATE_STATE_MAXIMIZED | YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_TILED))) return true; w->req_width = w->req_height = 0; w->size_pending = true; |
