diff --git a/backend/drm/drm.c b/backend/drm/drm.c index b2e2c3922..6655213b1 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -666,7 +666,7 @@ static bool drm_connector_state_update_primary_fb(struct wlr_drm_connector *conn return false; } - local_buf = drm_surface_blit(&plane->mgpu_surf, source_buf); + local_buf = drm_surface_blit(drm, &plane->mgpu_surf, source_buf); if (local_buf == NULL) { return false; } @@ -1048,7 +1048,7 @@ static bool drm_connector_set_cursor(struct wlr_output *output, return false; } - local_buf = drm_surface_blit(&plane->mgpu_surf, buffer); + local_buf = drm_surface_blit(drm, &plane->mgpu_surf, buffer); if (local_buf == NULL) { return false; } diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index e4aadc106..93564f7a7 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -12,6 +12,20 @@ #include "render/pixel_format.h" #include "render/wlr_renderer.h" +static void handle_lost_mgpu_renderer(struct wlr_drm_backend *drm) { + wlr_log(WLR_DEBUG, "Handling lost renderer"); + for (size_t i = 0; i < drm->num_planes; ++i) { + struct wlr_drm_plane *plane = &drm->planes[i]; + finish_drm_surface(&plane->mgpu_surf); + } + finish_drm_renderer(&drm->mgpu_renderer); + + if (!init_drm_renderer(drm, &drm->mgpu_renderer)) { + wlr_log(WLR_ERROR, "Failed to initialize renderer"); + return; + } +} + bool init_drm_renderer(struct wlr_drm_backend *drm, struct wlr_drm_renderer *renderer) { renderer->wlr_rend = renderer_autocreate_with_drm_fd(drm->fd); @@ -73,8 +87,8 @@ bool init_drm_surface(struct wlr_drm_surface *surf, return true; } -struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf, - struct wlr_buffer *buffer) { +struct wlr_buffer *drm_surface_blit(struct wlr_drm_backend *drm, + struct wlr_drm_surface *surf, struct wlr_buffer *buffer) { struct wlr_renderer *renderer = surf->renderer->wlr_rend; if (surf->swapchain->width != buffer->width || @@ -118,6 +132,9 @@ error_dst: wlr_buffer_unlock(dst); error_tex: wlr_texture_destroy(tex); + if (renderer->lost) { + handle_lost_mgpu_renderer(drm); + } return NULL; } diff --git a/include/backend/drm/renderer.h b/include/backend/drm/renderer.h index f53f720bc..0fc060b2f 100644 --- a/include/backend/drm/renderer.h +++ b/include/backend/drm/renderer.h @@ -31,8 +31,8 @@ bool init_drm_surface(struct wlr_drm_surface *surf, const struct wlr_drm_format *drm_format); void finish_drm_surface(struct wlr_drm_surface *surf); -struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf, - struct wlr_buffer *buffer); +struct wlr_buffer *drm_surface_blit(struct wlr_drm_backend *drm, + struct wlr_drm_surface *surf, struct wlr_buffer *buffer); bool drm_plane_pick_render_format(struct wlr_drm_plane *plane, struct wlr_drm_format *fmt, struct wlr_drm_renderer *renderer); diff --git a/include/wlr/render/wlr_renderer.h b/include/wlr/render/wlr_renderer.h index bb9a55fcf..55d28f073 100644 --- a/include/wlr/render/wlr_renderer.h +++ b/include/wlr/render/wlr_renderer.h @@ -29,6 +29,7 @@ struct wlr_renderer { // Capabilities required for the buffer used as a render target (bitmask of // enum wlr_buffer_cap) uint32_t render_buffer_caps; + bool lost; struct { struct wl_signal destroy; diff --git a/render/gles2/pass.c b/render/gles2/pass.c index 9177b0a1f..bfa8781f1 100644 --- a/render/gles2/pass.c +++ b/render/gles2/pass.c @@ -255,6 +255,7 @@ struct wlr_gles2_render_pass *begin_gles2_buffer_pass(struct wlr_gles2_buffer *b GLenum status = renderer->procs.glGetGraphicsResetStatusKHR(); if (status != GL_NO_ERROR) { wlr_log(WLR_ERROR, "GPU reset (%s)", reset_status_str(status)); + renderer->wlr_renderer.lost = true; wl_signal_emit_mutable(&renderer->wlr_renderer.events.lost, NULL); return NULL; } diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 590372ebe..f15faf1ba 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -38,6 +38,7 @@ void wlr_renderer_init(struct wlr_renderer *renderer, *renderer = (struct wlr_renderer){ .impl = impl, .render_buffer_caps = render_buffer_caps, + .lost = false, }; wl_signal_init(&renderer->events.destroy);