]> git.mdlowis.com Git - proto/labwc.git/commitdiff
backend/drm: Implement support for renderer loss recovery
authorChristopher Snowhill <kode54@gmail.com>
Thu, 18 Jul 2024 00:13:51 +0000 (17:13 -0700)
committerConsolatis <35009135+Consolatis@users.noreply.github.com>
Tue, 23 Jul 2024 12:44:31 +0000 (14:44 +0200)
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.

include/labwc.h
include/magnifier.h
src/magnifier.c
src/server.c

index 468da5b5a9fdba7d17f23ea8772ca1abc9c2a2d1..77bb41d4cfeee61920191cde5167111ede250508 100644 (file)
@@ -318,6 +318,8 @@ struct server {
         */
        int pending_output_layout_change;
 
+       struct wl_listener renderer_lost;
+
        struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1;
        struct wl_listener gamma_control_set_gamma;
 
index 60005458d54d7a6acfd124ed3d1cd2f1103b99bf..daa6d7a38a37c2e52809a9b769f1fdd89374498d 100644 (file)
@@ -20,5 +20,6 @@ bool output_wants_magnification(struct output *output);
 void magnify(struct output *output, struct wlr_buffer *output_buffer,
        struct wlr_box *damage);
 bool is_magnify_on(void);
+void magnify_reset(void);
 
 #endif /* LABWC_MAGNIFIER_H */
index 243455aa49cd7e24c4556a557f82eb223e945cb3..fded35fded21b9019404fc98c459074f9427fd81 100644 (file)
 static bool magnify_on;
 static double mag_scale = 0.0;
 
+/* Reuse a single scratch buffer */
+static struct wlr_buffer *tmp_buffer = NULL;
+static struct wlr_texture *tmp_texture = NULL;
+
 #define CLAMP(in, lower, upper) MAX(MIN((in), (upper)), (lower))
 
 void
@@ -21,10 +25,6 @@ magnify(struct output *output, struct wlr_buffer *output_buffer, struct wlr_box
        struct wlr_fbox src_box;
        bool fullscreen = false;
 
-       /* Reuse a single scratch buffer */
-       static struct wlr_buffer *tmp_buffer = NULL;
-       static struct wlr_texture *tmp_texture = NULL;
-
        /* TODO: This looks way too complicated to just get the used format */
        struct wlr_drm_format wlr_drm_format = {0};
        struct wlr_shm_attributes shm_attribs = {0};
@@ -125,6 +125,10 @@ magnify(struct output *output, struct wlr_buffer *output_buffer, struct wlr_box
        /* Extract source region into temporary buffer */
        struct wlr_render_pass *tmp_render_pass = wlr_renderer_begin_buffer_pass(
                server->renderer, tmp_buffer, NULL);
+       if (!tmp_render_pass) {
+               wlr_log(WLR_ERROR, "Failed to begin magnifier render pass");
+               return;
+       }
 
        wlr_buffer_lock(output_buffer);
        struct wlr_texture *output_texture = wlr_texture_from_buffer(
@@ -152,6 +156,10 @@ magnify(struct output *output, struct wlr_buffer *output_buffer, struct wlr_box
        /* Render to the output buffer itself */
        tmp_render_pass = wlr_renderer_begin_buffer_pass(
                server->renderer, output_buffer, NULL);
+       if (!tmp_render_pass) {
+               wlr_log(WLR_ERROR, "Failed to begin second magnifier render pass");
+               goto cleanup;
+       }
 
        /* Borders */
        if (fullscreen) {
@@ -286,6 +294,18 @@ magnify_set_scale(struct server *server, enum magnify_dir dir)
        }
 }
 
+/* Reset any buffers held by the magnifier */
+void
+magnify_reset(void)
+{
+       if (tmp_texture && tmp_buffer) {
+               wlr_texture_destroy(tmp_texture);
+               wlr_buffer_drop(tmp_buffer);
+               tmp_buffer = NULL;
+               tmp_texture = NULL;
+       }
+}
+
 /* Report whether magnification is enabled */
 bool
 is_magnify_on(void)
index b8beee2caf2af4081023fe8ab265ccca695bcd23..7f1caa304afbe4fe155c57d9a462c96dccaf5e19 100644 (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);
 
        /*