diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 127c87787..c57509332 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -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: