backend/drm: Implement support for renderer loss recovery

This implementation is nearly identical to Sway's, except that
it also reloads the configuration, to spur on reloading the
server-side decorations.

v2: Fix style.
v3: Add a reset to the magnifier.
v4: Oops, restructure reset handler a bit.
v5: Commit the magnifier reset immediately, before freeing the
    lost allocator and renderer.
v6: Also check for failed render pass, which may return NULL.
v7: Add a second NULL test, just in case.
This commit is contained in:
Christopher Snowhill 2024-07-17 17:13:51 -07:00 committed by Consolatis
parent e934c7a417
commit 3879f1f080
4 changed files with 76 additions and 4 deletions

View file

@ -28,6 +28,7 @@
#include "idle.h"
#include "labwc.h"
#include "layers.h"
#include "magnifier.h"
#include "menu/menu.h"
#include "output-state.h"
#include "output-virtual.h"
@ -249,6 +250,51 @@ get_headless_backend(struct wlr_backend *backend, void *data)
}
}
static void
handle_renderer_lost(struct wl_listener *listener, void *data)
{
struct server *server = wl_container_of(listener, server, renderer_lost);
wlr_log(WLR_INFO, "Re-creating renderer after GPU reset");
struct wlr_renderer *renderer = wlr_renderer_autocreate(server->backend);
if (!renderer) {
wlr_log(WLR_ERROR, "Unable to create renderer");
return;
}
struct wlr_allocator *allocator =
wlr_allocator_autocreate(server->backend, renderer);
if (!allocator) {
wlr_log(WLR_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(compositor, renderer);
struct output *output;
wl_list_for_each(output, &server->outputs, link) {
wlr_output_init_render(output->wlr_output,
server->allocator, server->renderer);
}
reload_config_and_theme(server);
magnify_reset();
wlr_allocator_destroy(old_allocator);
wlr_renderer_destroy(old_renderer);
}
void
server_init(struct server *server)
{
@ -336,6 +382,9 @@ server_init(struct server *server)
exit(EXIT_FAILURE);
}
server->renderer_lost.notify = handle_renderer_lost;
wl_signal_add(&server->renderer->events.lost, &server->renderer_lost);
wlr_renderer_init_wl_display(server->renderer, server->wl_display);
/*