renderer-gl: recreate SHM buffers in GPU recovery

Call gl_renderer_attach_shm() to recreate all the SHM buffer states
in the new EGL context. This can enable non-GL applications to
continue running without crashing during GPU reset and recovery
processes, as if no GPU reset had ever occurred.

Signed-off-by: Trigger Huang <Trigger.Huang@amd.com>
This commit is contained in:
Trigger Huang 2026-04-24 14:47:44 +08:00
parent 49732c40c1
commit 9730192811

View file

@ -304,6 +304,7 @@ struct gl_buffer_state {
struct wl_listener destroy_listener;
struct wl_list link; /* link to shm_bufs of gl renderer */
void *saved_gs; /* gl_surface_state, saved for gb recreation */
};
struct gl_surface_state {
@ -3599,7 +3600,7 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer)
* than allocating a new one. */
assert(!gs->buffer ||
(old_buffer && old_buffer->type == WESTON_BUFFER_SHM));
if (gs->buffer &&
if (gs->buffer && !gr->recovering &&
buffer->width == old_buffer->width &&
buffer->height == old_buffer->height &&
buffer->pixel_format == old_buffer->pixel_format) {
@ -3614,6 +3615,7 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer)
gb = xzalloc(sizeof(*gb));
gb->gr = gr;
gb->saved_gs = gs;
wl_list_init(&gb->destroy_listener.link);
wl_list_init(&gb->link);
@ -3641,7 +3643,9 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer)
false);
}
wl_list_insert(&gr->shm_bufs, &gb->link);
/* For recovery, we will manually add the new gb to shm_bufs. */
if (!gr->recovering)
wl_list_insert(&gr->shm_bufs, &gb->link);
}
static bool
@ -5168,6 +5172,7 @@ gl_renderer_destroy_context(struct weston_compositor *ec)
struct gl_renderer *gr = get_renderer(ec);
struct dmabuf_format *format, *next_format;
struct gl_capture_task *gl_task, *tmp;
struct gl_buffer_state *gb;
if (gr->display_bound) {
gr->unbind_display(gr->egl_display, ec->wl_display);
@ -5199,6 +5204,18 @@ gl_renderer_destroy_context(struct weston_compositor *ec)
ec->dmabuf_feedback_format_table = NULL;
}
/*
* Destroy the GL textures of the SHM buffer as they are invalid in the
* new context. gl_renderer_attach_shm() will be called after recovery
* to recreate all the SHM buffer states.
*/
if (gr->recovering) {
wl_list_for_each(gb, &gr->shm_bufs, link) {
glDeleteTextures(gb->num_textures, gb->textures);
gb->num_textures = 0;
}
}
wl_list_for_each_safe(format, next_format, &gr->dmabuf_formats, link)
dmabuf_format_destroy(format);
@ -5279,6 +5296,62 @@ create_default_dmabuf_feedback(struct weston_compositor *ec,
return 0;
}
static int
gl_renderer_recover_resources(struct weston_compositor *ec)
{
struct gl_renderer *gr = get_renderer(ec);
struct gl_buffer_state *gb, *tmp;
struct wl_list tmp_gb_list;
wl_list_init(&tmp_gb_list);
wl_list_for_each_safe(gb, tmp, &gr->shm_bufs, link) {
struct gl_surface_state *gs = gb->saved_gs;
struct weston_surface *es = gs->surface;
struct gl_buffer_state *new_gb;
struct weston_buffer *buffer;
assert(es);
/*
* This gb is no longer the surface's current SHM buffer state.
* It has lost its owner link through gs->buffer, so the normal
* surface lifecycle will not destroy it for us anymore. Treat it
* as an orphaned stale entry and clean it up here.
*/
if (gs->buffer != gb) {
destroy_buffer_state(gb);
continue;
}
/* Destroy the original gb and recreate it. */
buffer = es->buffer_ref.buffer;
if (!buffer || buffer->type != WESTON_BUFFER_SHM) {
/*
* The surface no longer points at a live SHM buffer, so
* this gb should not participate in GPU recovery.
* However, gs->buffer still owns it, and the normal
* attach/surface-destroy paths will destroy it later.
* Remove it from shm_bufs so recovery ignores it, but do
* not change its original lifetime.
*/
wl_list_remove(&gb->link);
wl_list_init(&gb->link);
continue;
}
gl_renderer_attach_shm(es, buffer);
new_gb = gs->buffer;
assert(new_gb);
wl_list_insert(&tmp_gb_list, &new_gb->link);
}
assert(wl_list_empty(&gr->shm_bufs));
/* Manually add the new gbs to shm_bufs. */
wl_list_insert_list(&gr->shm_bufs, &tmp_gb_list);
return 0;
}
static int
gl_renderer_init_context(struct weston_compositor *ec,
const struct gl_renderer_display_options *options)
@ -5370,6 +5443,9 @@ gl_renderer_init_context(struct weston_compositor *ec,
}
wl_list_init(&gr->dmabuf_formats);
if (gr->recovering && gl_renderer_recover_resources(ec))
goto fail_with_error;
return 0;
fail_with_error: