From 3bc75221bc0074b2e96e14cb88140c95406472c3 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 14 Mar 2024 13:54:08 +0100 Subject: [PATCH] Re-create renderer when lost --- include/sway/server.h | 1 + sway/server.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/sway/server.h b/include/sway/server.h index b2eb2c36..c71851f6 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -46,6 +46,7 @@ struct sway_server { struct wl_listener new_output; struct wl_listener output_layout_change; + struct wl_listener renderer_lost; struct wlr_idle_notifier_v1 *idle_notifier_v1; struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1; diff --git a/sway/server.c b/sway/server.c index 94d0fae2..51bde794 100644 --- a/sway/server.c +++ b/sway/server.c @@ -172,6 +172,45 @@ static void detect_proprietary(struct wlr_backend *backend, void *data) { drmFreeVersion(version); } +static void handle_renderer_lost(struct wl_listener *listener, void *data) { + struct sway_server *server = wl_container_of(listener, server, renderer_lost); + + sway_log(SWAY_INFO, "Re-creating renderer after GPU reset"); + + struct wlr_renderer *renderer = wlr_renderer_autocreate(server->backend); + if (renderer == NULL) { + sway_log(SWAY_ERROR, "Unable to create renderer"); + return; + } + + struct wlr_allocator *allocator = + wlr_allocator_autocreate(server->backend, renderer); + if (allocator == NULL) { + sway_log(SWAY_ERROR, "Unable to create allocator"); + wlr_renderer_destroy(renderer); + return; + } + + struct wlr_renderer *old_renderer = server->renderer; + struct wlr_allocator *old_allocator = server->allocator; + server->renderer = renderer; + server->allocator = allocator; + + wl_list_remove(&server->renderer_lost.link); + wl_signal_add(&server->renderer->events.lost, &server->renderer_lost); + + wlr_compositor_set_renderer(server->compositor, renderer); + + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + wlr_output_init_render(output->wlr_output, + server->allocator, server->renderer); + } + + wlr_allocator_destroy(old_allocator); + wlr_renderer_destroy(old_renderer); +} + bool server_init(struct sway_server *server) { sway_log(SWAY_DEBUG, "Initializing Wayland server"); server->wl_display = wl_display_create(); @@ -195,6 +234,9 @@ bool server_init(struct sway_server *server) { return false; } + server->renderer_lost.notify = handle_renderer_lost; + wl_signal_add(&server->renderer->events.lost, &server->renderer_lost); + wlr_renderer_init_wl_shm(server->renderer, server->wl_display); if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL) {