diff --git a/clients/simple-egl.c b/clients/simple-egl.c index 7cc98ea36..20b909a6c 100644 --- a/clients/simple-egl.c +++ b/clients/simple-egl.c @@ -39,6 +39,8 @@ #include #include +#include +#include #include #include @@ -86,6 +88,7 @@ struct display { PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage; PFNEGLQUERYSUPPORTEDCOMPRESSIONRATESEXTPROC query_compression_rates; + PFNGLGETGRAPHICSRESETSTATUSEXTPROC get_graphics_reset_status; }; struct geometry { @@ -106,6 +109,9 @@ struct window { GLuint rotation_uniform; GLuint pos; GLuint col; + GLuint frag; + GLuint vert; + GLuint program; } gl; uint32_t frames; @@ -200,7 +206,9 @@ init_egl(struct display *display, struct window *window) }; static const EGLint context_attribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_CLIENT_VERSION, 3, + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, + EGL_LOSE_CONTEXT_ON_RESET_KHR, EGL_NONE }; const char *extensions; @@ -310,6 +318,18 @@ init_egl(struct display *display, struct window *window) eglGetProcAddress("eglQuerySupportedCompressionRatesEXT"); printf("has EGL_EXT_surface_compression\n"); } + + if (extensions && + weston_check_egl_extension(extensions, + "EGL_EXT_create_context_robustness")) { + display->get_graphics_reset_status = + (PFNGLGETGRAPHICSRESETSTATUSEXTPROC) + eglGetProcAddress("glGetGraphicsResetStatusEXT"); + if (display->get_graphics_reset_status) + printf("glGetGraphicsResetStatusEXT is valid!\n"); + else + printf("glGetGraphicsResetStatusEXT is invalid!\n"); + } } static void @@ -319,6 +339,21 @@ fini_egl(struct display *display) eglReleaseThread(); } +static void +fini_gl(struct window *window) +{ + glDeleteShader(window->gl.frag); + glDeleteShader(window->gl.vert); + glDeleteProgram(window->gl.program); + + eglMakeCurrent(window->display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + + weston_platform_destroy_egl_surface(window->display->egl.dpy, + window->egl_surface); + wl_egl_window_destroy(window->native); +} + static GLuint create_shader(struct window *window, const char *source, GLenum shader_type) { @@ -477,6 +512,7 @@ init_gl(struct window *window) EGLBoolean ret; EGLint attribs[5] = { EGL_NONE }; uint32_t num_attribs = 0; + GLint strategy = 0; if (window->needs_buffer_geometry_update) update_buffer_geometry(window); @@ -561,12 +597,21 @@ init_gl(struct window *window) window->gl.pos = 0; window->gl.col = 1; + window->gl.frag = frag; + window->gl.vert = vert; + window->gl.program = program; glBindAttribLocation(program, window->gl.pos, "pos"); glBindAttribLocation(program, window->gl.col, "color"); window->gl.rotation_uniform = glGetUniformLocation(program, "rotation"); + + glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_EXT, &strategy); + if (strategy == GL_LOSE_CONTEXT_ON_RESET_EXT) + printf("Create GL robust context successfully!\n"); + else + printf("Failed to create GL robust context successfully!\n"); } static void @@ -902,7 +947,37 @@ destroy_surface(struct window *window) } -static void +static int +check_gpu_reset_status(struct display *display) +{ + bool has_reset = false; + int i; + + if (!display->get_graphics_reset_status) + return 0; + + /* Assume GPU reset should be finished within 5s. */ + for (i = 0; i < 100000; i++) { + unsigned status; + + status = display->get_graphics_reset_status(); + if (status == GL_NO_ERROR) + break; + + has_reset = true; + usleep(50); + } + + if (!has_reset) + return 0; + + /* If GPU reset has not completed, nothing we can do. */ + assert(i < 100000); + + return -EAGAIN; +} + +static int redraw(struct window *window) { struct display *display = window->display; @@ -995,6 +1070,8 @@ redraw(struct window *window) draw_triangle(window, buffer_age); window->frames++; + + return check_gpu_reset_status(display); } static void @@ -1469,15 +1546,12 @@ main(int argc, char **argv) goto out_no_xdg_shell; } - init_egl(&display, &window); create_surface(&window); /* we already have wait_for_configure set after create_surface() */ while (running && ret != -1 && window.wait_for_configure) ret = wl_display_dispatch(display.display); - init_gl(&window); - display.cursor_surface = wl_compositor_create_surface(display.compositor); @@ -1486,13 +1560,25 @@ main(int argc, char **argv) sigint.sa_flags = SA_RESETHAND; sigaction(SIGINT, &sigint, NULL); +init_gl_egl: + init_egl(&display, &window); + init_gl(&window); + while (running && ret != -1) { + int draw; + ret = wl_display_dispatch_pending(display.display); - redraw(&window); + draw = redraw(&window); + if (draw) { + fini_gl(&window); + fini_egl(&display); + goto init_gl_egl; + } } fprintf(stderr, "simple-egl exiting\n"); + fini_gl(&window); destroy_surface(&window); fini_egl(&display); diff --git a/libweston/backend-drm/drm-gbm.c b/libweston/backend-drm/drm-gbm.c index f3caa035e..3bf196bd0 100644 --- a/libweston/backend-drm/drm-gbm.c +++ b/libweston/backend-drm/drm-gbm.c @@ -80,9 +80,13 @@ drm_backend_create_gl_renderer(struct drm_backend *b) if (format[1]) options.formats_count = 2; - return weston_compositor_init_renderer(b->compositor, - WESTON_RENDERER_GL, - &options.base); + if (!b->gl_recovering) + return weston_compositor_init_renderer(b->compositor, + WESTON_RENDERER_GL, + &options.base); + else + return b->compositor->renderer->gl->display_create(b->compositor, + &options); } static int @@ -525,24 +529,29 @@ drm_output_init_egl(struct drm_output *output, struct drm_backend *b) options.fb_size.width = mode->width; options.fb_size.height = mode->height; - assert(output->gbm_surface == NULL); - create_gbm_surface(b->gbm, output); - if (!output->gbm_surface) { - weston_log("failed to create gbm surface\n"); - return -1; + /* GBM surface and cursor do not need to be recreated when recovering */ + if (!b->gl_recovering) { + assert(output->gbm_surface == NULL); + create_gbm_surface(b->gbm, output); + if (!output->gbm_surface) { + weston_log("failed to create gbm surface\n"); + return -1; + } + + drm_output_init_cursor_egl(output, b); } options.window_for_legacy = (EGLNativeWindowType) output->gbm_surface; options.window_for_platform = output->gbm_surface; if (renderer->gl->output_window_create(&output->base, &options) < 0) { weston_log("failed to create gl renderer output state\n"); - gbm_surface_destroy(output->gbm_surface); - output->gbm_surface = NULL; + if (!b->gl_recovering) { + gbm_surface_destroy(output->gbm_surface); + output->gbm_surface = NULL; + } return -1; } - drm_output_init_cursor_egl(output, b); - return 0; } @@ -780,6 +789,82 @@ drm_output_fini_vulkan(struct drm_output *output) drm_output_fini_cursor_vulkan(output); } +static int +drm_handle_gl_renderer_error(struct weston_compositor *compositor, int err) +{ + const struct weston_renderer *renderer = compositor->renderer; + struct drm_backend *b = to_drm_backend(compositor); + int ret; + + switch (err) { + case WESTON_RENDERER_ERROR_LOST: { + struct weston_output *output; + + weston_log("Initiating GL renderer recovery...\n"); + b->gl_recovering = true; + renderer->gl->set_recovering(compositor, true); + + /* 1, Destroy the renderer outputs */ + wl_list_for_each(output, &compositor->output_list, link) { + struct drm_output *drm = to_drm_output(output); + struct drm_plane *scanout = drm->scanout_handle->plane; + + /* + * When the output is destroyed, its associated + * EGLSurface will also be destroyed. Consequently, the + * GBM BOs backing this surface will be freed. Mesa will + * destroy the GBM BO user_data (fb) regardless of + * refcount, so ensure we destroy them here before + * invoking output_destroy. + */ + if (scanout && scanout->state_cur && + scanout->state_cur->fb && + scanout->state_cur->fb->type == BUFFER_GBM_SURFACE) + drm_plane_reset_state(scanout); + + renderer->gl->output_destroy(output); + } + + /* 2, Destroy the renderer */ + renderer->destroy(compositor); + + /* 3, Create the renderer again */ + ret = drm_backend_create_gl_renderer(b); + if (ret < 0) { + weston_log("Failed to recreate gl renderer!\n"); + goto fail; + } + + /* 4, Create the renderer outputs again */ + wl_list_for_each(output, &compositor->output_list, link) { + ret = drm_output_init_egl(to_drm_output(output), b); + if (ret < 0) { + weston_log("Failed to recreate gl output!\n"); + goto fail; + } + } + + b->gl_recovering = false; + drm_device_recovery_required(b->drm); + renderer->gl->set_recovering(compositor, false); + ret = -EAGAIN; + + weston_log("GL renderer recovery completed successfully\n"); + break; + } + default: + weston_log("Unsupported gl renderer err: %d\n", err); + ret = -EINVAL; + } + + return ret; + +fail: + b->gl_recovering = false; + renderer->gl->set_recovering(compositor, false); + return -EIO; +} + struct drm_fb * drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage) { @@ -787,9 +872,19 @@ drm_output_render_gl(struct drm_output_state *state, pixman_region32_t *damage) struct drm_device *device = output->device; struct gbm_bo *bo; struct drm_fb *ret; + int err; - output->base.compositor->renderer->repaint_output(&output->base, - damage, NULL); +repaint: + err = output->base.compositor->renderer->repaint_output(&output->base, + damage, NULL); + + if (err != WESTON_RENDERER_ERROR_NONE) { + err = drm_handle_gl_renderer_error(output->base.compositor, err); + if (err == -EAGAIN) + goto repaint; + + return NULL; + } bo = gbm_surface_lock_front_buffer(output->gbm_surface); if (!bo) { diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index d4ba085d0..3471b71d3 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -285,6 +285,9 @@ struct drm_backend { bool timer_armed; } perf_page_flips_stats; + /* True, if GL renderer is recovering from GPU reset */ + bool gl_recovering; + /* True if we need a workaround for some very old kernels */ bool stale_timestamp_workaround; }; diff --git a/libweston/libweston-internal.h b/libweston/libweston-internal.h index 79212d0ce..9dc7c1781 100644 --- a/libweston/libweston-internal.h +++ b/libweston/libweston-internal.h @@ -82,10 +82,15 @@ enum weston_renderer_border_side { WESTON_RENDERER_BORDER_BOTTOM = 3, }; +enum weston_renderer_error { + WESTON_RENDERER_ERROR_NONE = 0, + WESTON_RENDERER_ERROR_LOST = 1, +}; + struct weston_renderer { - void (*repaint_output)(struct weston_output *output, - pixman_region32_t *output_damage, - weston_renderbuffer_t renderbuffer); + enum weston_renderer_error (*repaint_output)(struct weston_output *output, + pixman_region32_t *output_damage, + weston_renderbuffer_t renderbuffer); /** See weston_renderer_resize_output() * diff --git a/libweston/noop-renderer.c b/libweston/noop-renderer.c index a27bb827b..3694358a4 100644 --- a/libweston/noop-renderer.c +++ b/libweston/noop-renderer.c @@ -36,11 +36,12 @@ struct noop_renderer { unsigned char seed; /* see comment in attach() */ }; -static void +static enum weston_renderer_error noop_renderer_repaint_output(struct weston_output *output, pixman_region32_t *output_damage, weston_renderbuffer_t renderbuffer) { + return WESTON_RENDERER_ERROR_NONE; } static bool diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c index ca948e784..8f6e50a46 100644 --- a/libweston/pixman-renderer.c +++ b/libweston/pixman-renderer.c @@ -598,7 +598,7 @@ static void pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer); -static void +static enum weston_renderer_error pixman_renderer_repaint_output(struct weston_output *output, pixman_region32_t *output_damage, weston_renderbuffer_t renderbuffer) @@ -622,7 +622,7 @@ pixman_renderer_repaint_output(struct weston_output *output, output->color_outcome->from_blend_to_output == NULL); if (!po->hw_buffer) - return; + goto out; if (po->shadow_image) { repaint_surfaces(output, output_damage); @@ -641,6 +641,9 @@ pixman_renderer_repaint_output(struct weston_output *output, wl_signal_emit(&output->frame_signal, output_damage); /* Actual flip should be done by caller */ + +out: + return WESTON_RENDERER_ERROR_NONE; } static void diff --git a/libweston/renderer-gl/egl-glue.c b/libweston/renderer-gl/egl-glue.c index f26852923..decae10c2 100644 --- a/libweston/renderer-gl/egl-glue.c +++ b/libweston/renderer-gl/egl-glue.c @@ -73,6 +73,7 @@ static const struct gl_extension_table device_table[] = { static const struct gl_extension_table display_table[] = { EXT("EGL_ANDROID_native_fence_sync", EXTENSION_ANDROID_NATIVE_FENCE_SYNC), EXT("EGL_EXT_buffer_age", EXTENSION_EXT_BUFFER_AGE), + EXT("EGL_EXT_create_context_robustness", EXTENSION_EXT_CREATE_CONTEXT_ROBUSTNESS), EXT("EGL_EXT_image_dma_buf_import", EXTENSION_EXT_IMAGE_DMA_BUF_IMPORT), EXT("EGL_EXT_image_dma_buf_import_modifiers", EXTENSION_EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS), EXT("EGL_EXT_pixel_format_float", EXTENSION_EXT_PIXEL_FORMAT_FLOAT), diff --git a/libweston/renderer-gl/gl-renderer-internal.h b/libweston/renderer-gl/gl-renderer-internal.h index 87bd70132..5ae3204b3 100644 --- a/libweston/renderer-gl/gl-renderer-internal.h +++ b/libweston/renderer-gl/gl-renderer-internal.h @@ -106,21 +106,22 @@ enum egl_device_extension_flag { enum egl_display_extension_flag { EXTENSION_ANDROID_NATIVE_FENCE_SYNC = 1ull << 0, EXTENSION_EXT_BUFFER_AGE = 1ull << 1, - EXTENSION_EXT_IMAGE_DMA_BUF_IMPORT = 1ull << 2, - EXTENSION_EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS = 1ull << 3, - EXTENSION_EXT_PIXEL_FORMAT_FLOAT = 1ull << 4, - EXTENSION_EXT_SWAP_BUFFERS_WITH_DAMAGE = 1ull << 5, - EXTENSION_IMG_CONTEXT_PRIORITY = 1ull << 6, - EXTENSION_KHR_FENCE_SYNC = 1ull << 7, - EXTENSION_KHR_GET_ALL_PROC_ADDRESSES = 1ull << 8, - EXTENSION_KHR_IMAGE_BASE = 1ull << 9, - EXTENSION_KHR_NO_CONFIG_CONTEXT = 1ull << 10, - EXTENSION_KHR_PARTIAL_UPDATE = 1ull << 11, - EXTENSION_KHR_SURFACELESS_CONTEXT = 1ull << 12, - EXTENSION_KHR_SWAP_BUFFERS_WITH_DAMAGE = 1ull << 13, - EXTENSION_KHR_WAIT_SYNC = 1ull << 14, - EXTENSION_MESA_CONFIGLESS_CONTEXT = 1ull << 15, - EXTENSION_WL_BIND_WAYLAND_DISPLAY = 1ull << 16, + EXTENSION_EXT_CREATE_CONTEXT_ROBUSTNESS = 1ull << 2, + EXTENSION_EXT_IMAGE_DMA_BUF_IMPORT = 1ull << 3, + EXTENSION_EXT_IMAGE_DMA_BUF_IMPORT_MODIFIERS = 1ull << 4, + EXTENSION_EXT_PIXEL_FORMAT_FLOAT = 1ull << 5, + EXTENSION_EXT_SWAP_BUFFERS_WITH_DAMAGE = 1ull << 6, + EXTENSION_IMG_CONTEXT_PRIORITY = 1ull << 7, + EXTENSION_KHR_FENCE_SYNC = 1ull << 8, + EXTENSION_KHR_GET_ALL_PROC_ADDRESSES = 1ull << 9, + EXTENSION_KHR_IMAGE_BASE = 1ull << 10, + EXTENSION_KHR_NO_CONFIG_CONTEXT = 1ull << 11, + EXTENSION_KHR_PARTIAL_UPDATE = 1ull << 12, + EXTENSION_KHR_SURFACELESS_CONTEXT = 1ull << 13, + EXTENSION_KHR_SWAP_BUFFERS_WITH_DAMAGE = 1ull << 14, + EXTENSION_KHR_WAIT_SYNC = 1ull << 15, + EXTENSION_MESA_CONFIGLESS_CONTEXT = 1ull << 16, + EXTENSION_WL_BIND_WAYLAND_DISPLAY = 1ull << 17, }; /* Keep in sync with gl-renderer.c. */ @@ -134,27 +135,28 @@ enum gl_extension_flag { EXTENSION_EXT_EGL_IMAGE_STORAGE = 1ull << 8, EXTENSION_EXT_MAP_BUFFER_RANGE = 1ull << 9, EXTENSION_EXT_READ_FORMAT_BGRA = 1ull << 10, - EXTENSION_EXT_SHADER_FB_FETCH_NC = 1ull << 11, - EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888 = 1ull << 12, - EXTENSION_EXT_TEXTURE_NORM16 = 1ull << 13, - EXTENSION_EXT_TEXTURE_RG = 1ull << 14, - EXTENSION_EXT_TEXTURE_SRGB_R8 = 1ull << 15, - EXTENSION_EXT_TEXTURE_SRGB_RG8 = 1ull << 16, - EXTENSION_EXT_TEXTURE_STORAGE = 1ull << 17, - EXTENSION_EXT_TEXTURE_TYPE_2_10_10_10_REV = 1ull << 18, - EXTENSION_EXT_UNPACK_SUBIMAGE = 1ull << 19, - EXTENSION_NV_PACKED_FLOAT = 1ull << 20, - EXTENSION_NV_PIXEL_BUFFER_OBJECT = 1ull << 21, - EXTENSION_OES_EGL_IMAGE = 1ull << 22, - EXTENSION_OES_EGL_IMAGE_EXTERNAL = 1ull << 23, - EXTENSION_OES_MAPBUFFER = 1ull << 24, - EXTENSION_OES_REQUIRED_INTERNALFORMAT = 1ull << 25, - EXTENSION_OES_RGB8_RGBA8 = 1ull << 26, - EXTENSION_OES_TEXTURE_3D = 1ull << 27, - EXTENSION_OES_TEXTURE_FLOAT = 1ull << 28, - EXTENSION_OES_TEXTURE_FLOAT_LINEAR = 1ull << 29, - EXTENSION_OES_TEXTURE_HALF_FLOAT = 1ull << 30, - EXTENSION_QCOM_RENDER_SRGB_R8_RG8 = 1ull << 31, + EXTENSION_EXT_ROBUSTNESS = 1ull << 11, + EXTENSION_EXT_SHADER_FB_FETCH_NC = 1ull << 12, + EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888 = 1ull << 13, + EXTENSION_EXT_TEXTURE_NORM16 = 1ull << 14, + EXTENSION_EXT_TEXTURE_RG = 1ull << 15, + EXTENSION_EXT_TEXTURE_SRGB_R8 = 1ull << 16, + EXTENSION_EXT_TEXTURE_SRGB_RG8 = 1ull << 17, + EXTENSION_EXT_TEXTURE_STORAGE = 1ull << 18, + EXTENSION_EXT_TEXTURE_TYPE_2_10_10_10_REV = 1ull << 19, + EXTENSION_EXT_UNPACK_SUBIMAGE = 1ull << 20, + EXTENSION_NV_PACKED_FLOAT = 1ull << 21, + EXTENSION_NV_PIXEL_BUFFER_OBJECT = 1ull << 22, + EXTENSION_OES_EGL_IMAGE = 1ull << 23, + EXTENSION_OES_EGL_IMAGE_EXTERNAL = 1ull << 24, + EXTENSION_OES_MAPBUFFER = 1ull << 25, + EXTENSION_OES_REQUIRED_INTERNALFORMAT = 1ull << 26, + EXTENSION_OES_RGB8_RGBA8 = 1ull << 27, + EXTENSION_OES_TEXTURE_3D = 1ull << 28, + EXTENSION_OES_TEXTURE_FLOAT = 1ull << 29, + EXTENSION_OES_TEXTURE_FLOAT_LINEAR = 1ull << 30, + EXTENSION_OES_TEXTURE_HALF_FLOAT = 1ull << 31, + EXTENSION_QCOM_RENDER_SRGB_R8_RG8 = 1ull << 32, }; enum gl_feature_flag { @@ -208,6 +210,9 @@ enum gl_feature_flag { /* GL renderer can do blending explicitly in the fragment shader, * using framebuffer fetch and store curves. */ FEATURE_SHADER_BLENDING = 1ull << 10, + + /* The GL renderer can recover from a GPU reset. */ + FEATURE_GRAPHICS_RESET_RECOVERY = 1ull << 11, }; /* Keep the following in sync with vertex.glsl. */ @@ -521,6 +526,9 @@ struct gl_renderer { PFNGLTEXSTORAGE2DEXTPROC tex_storage_2d; PFNGLTEXSTORAGE3DEXTPROC tex_storage_3d; + /* GL_EXT_robustness */ + PFNGLGETGRAPHICSRESETSTATUSEXTPROC get_graphics_reset_status; + /* GL_EXT_shader_framebuffer_fetch_non_coherent */ PFNGLFRAMEBUFFERFETCHBARRIEREXTPROC framebuffer_fetch_barrier; @@ -532,7 +540,10 @@ struct gl_renderer { int max_combined_texture_image_units; bool blend_state; + bool recovering; + struct wl_list dma_bufs; + struct wl_list shm_bufs; struct wl_list dmabuf_images; struct wl_list dmabuf_formats; struct wl_list pending_capture_list; diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c index 5eb45f6cd..30f24c03f 100644 --- a/libweston/renderer-gl/gl-renderer.c +++ b/libweston/renderer-gl/gl-renderer.c @@ -303,6 +303,11 @@ struct gl_buffer_state { int num_textures; 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 linux_dmabuf_buffer *saved_dmabuf; + struct weston_buffer *saved_buffer; }; struct gl_surface_state { @@ -343,6 +348,7 @@ static const struct gl_extension_table extension_table[] = { EXT("GL_EXT_EGL_image_storage", EXTENSION_EXT_EGL_IMAGE_STORAGE), EXT("GL_EXT_map_buffer_range", EXTENSION_EXT_MAP_BUFFER_RANGE), EXT("GL_EXT_read_format_bgra", EXTENSION_EXT_READ_FORMAT_BGRA), + EXT("GL_EXT_robustness", EXTENSION_EXT_ROBUSTNESS), EXT("GL_EXT_shader_framebuffer_fetch_non_coherent", EXTENSION_EXT_SHADER_FB_FETCH_NC), EXT("GL_EXT_texture_format_BGRA8888", EXTENSION_EXT_TEXTURE_FORMAT_BGRA8888), EXT("GL_EXT_texture_norm16", EXTENSION_EXT_TEXTURE_NORM16), @@ -3130,6 +3136,37 @@ blit_shadow_to_output(struct weston_output *output, pixman_region32_fini(&translated_damage); } +static int +gl_renderer_check_reset(struct gl_renderer *gr) +{ + bool has_reset = false; + int i; + + if (!gl_features_has(gr, FEATURE_GRAPHICS_RESET_RECOVERY) || + !gr->get_graphics_reset_status) + return 0; + + /* Assume GPU reset should be finished within 5s. */ + for (i = 0; i < 100000; i++) { + GLenum status; + + status = gr->get_graphics_reset_status(); + if (status == GL_NO_ERROR) + break; + + has_reset = true; + usleep(50); + } + + if (!has_reset) + return 0; + + /* If GPU reset has not completed, nothing we can do. */ + assert(i < 100000); + + return -EAGAIN; +} + /* NOTE: We now allow falling back to ARGB gl visuals when XRGB is * unavailable, so we're assuming the background has no transparency * and that everything with a blend, like drop shadows, will have something @@ -3138,7 +3175,7 @@ blit_shadow_to_output(struct weston_output *output, * Depending on the underlying hardware, violating that assumption could * result in seeing through to another display plane. */ -static void +static enum weston_renderer_error gl_renderer_repaint_output(struct weston_output *output, pixman_region32_t *output_damage, weston_renderbuffer_t renderbuffer) @@ -3164,7 +3201,7 @@ gl_renderer_repaint_output(struct weston_output *output, go->fb_size.height - go->area.height - go->area.y : go->area.y; if (use_output(output) < 0) - return; + goto out; rb = gl_renderer_update_renderbuffers(output, output_damage, renderbuffer); @@ -3365,6 +3402,12 @@ gl_renderer_repaint_output(struct weston_output *output, gr->wireframe_dirty = false; gl_renderer_garbage_collect_programs(gr); + + if (gl_renderer_check_reset(gr)) + return WESTON_RENDERER_ERROR_LOST; + +out: + return WESTON_RENDERER_ERROR_NONE; } static void @@ -3481,6 +3524,7 @@ destroy_buffer_state(struct gl_buffer_state *gb) pixman_region32_fini(&gb->texture_damage); wl_list_remove(&gb->destroy_listener.link); + wl_list_remove(&gb->link); free(gb); } @@ -3609,7 +3653,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) { @@ -3624,8 +3668,10 @@ 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); pixman_region32_init(&gb->texture_damage); gb->pitch = pitch; @@ -3649,6 +3695,10 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer) texture_format[i].swizzles.array, false); } + + /* 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 @@ -3674,6 +3724,7 @@ gl_renderer_fill_buffer_info(struct weston_compositor *ec, gb->gr = gr; pixman_region32_init(&gb->texture_damage); + wl_list_init(&gb->link); buffer->legacy_buffer = (struct wl_buffer *)buffer->resource; ret &= gr->query_buffer(gr->egl_display, buffer->legacy_buffer, @@ -4135,6 +4186,7 @@ import_dmabuf(struct gl_renderer *gr, gb->gr = gr; pixman_region32_init(&gb->texture_damage); wl_list_init(&gb->destroy_listener.link); + wl_list_init(&gb->link); quirks = &gr->compositor->test_data.test_quirks; if (quirks->gl_force_import_yuv_fallback && @@ -4305,6 +4357,8 @@ gl_renderer_import_dmabuf(struct weston_compositor *ec, if (!gb) return false; + wl_list_insert(&gr->dma_bufs, &gb->link); + gb->saved_dmabuf = dmabuf; linux_dmabuf_buffer_set_user_data(dmabuf, gb, gl_renderer_destroy_dmabuf); @@ -4321,6 +4375,8 @@ gl_renderer_attach_buffer(struct weston_surface *surface, assert(buffer->renderer_private); gb = buffer->renderer_private; gs->buffer = gb; + gb->saved_gs = gs; + gb->saved_buffer = buffer; } static const struct weston_drm_format_array * @@ -4414,6 +4470,13 @@ gl_renderer_attach(struct weston_paint_node *pnode) gs->buffer = NULL; } } else { + if (gs->buffer) { + /* + * Non-SHM buffer state is buffer-owned. Clear the saved + * surface link before dropping gs->buffer. + */ + gs->buffer->saved_gs = NULL; + } gs->buffer = NULL; } @@ -4472,6 +4535,9 @@ gl_renderer_buffer_init(struct weston_compositor *etc, assert(gb); linux_dmabuf_buffer_set_user_data(buffer->dmabuf, NULL, NULL); buffer->renderer_private = gb; + gb->saved_gs = NULL; + gb->saved_dmabuf = NULL; + gb->saved_buffer = buffer; gb->destroy_listener.notify = handle_buffer_destroy; wl_signal_add(&buffer->destroy_signal, &gb->destroy_listener); } @@ -4599,6 +4665,9 @@ surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr) if (gs->buffer && gs->buffer_ref.buffer->type == WESTON_BUFFER_SHM) destroy_buffer_state(gs->buffer); + else if (gs->buffer) + /* Clear the saved surface link for buffer-owned state */ + gs->buffer->saved_gs = NULL; gs->buffer = NULL; weston_buffer_reference(&gs->buffer_ref, NULL, @@ -5163,23 +5232,27 @@ gl_renderer_allocator_create(struct gl_renderer *gr, } static void -gl_renderer_destroy(struct weston_compositor *ec) +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; - wl_signal_emit(&gr->destroy_signal, gr); - - if (gr->display_bound) + if (gr->display_bound) { gr->unbind_display(gr->egl_display, ec->wl_display); + gr->display_bound = false; + } wl_list_for_each_safe(gl_task, tmp, &gr->pending_capture_list, link) destroy_capture_task(gl_task); gl_renderer_shader_list_destroy(gr); - if (gr->fallback_shader) + if (gr->fallback_shader) { gl_shader_destroy(gr, gr->fallback_shader); + gr->fallback_shader = NULL; + } + gr->current_shader = NULL; if (gr->wireframe_tex) gl_texture_fini(&gr->wireframe_tex); @@ -5189,16 +5262,79 @@ gl_renderer_destroy(struct weston_compositor *ec) EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (gr->recovering && gr->drm_device) { + weston_dmabuf_feedback_destroy(ec->default_dmabuf_feedback); + ec->default_dmabuf_feedback = NULL; + weston_dmabuf_feedback_format_table_destroy(ec->dmabuf_feedback_format_table); + 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; + } + + /* Destroy all the GL/EGL resources for dma-bufs. */ + wl_list_for_each(gb, &gr->dma_bufs, link) { + struct gl_color_egl_image *color_egl_image; + int i; + + glDeleteTextures(gb->num_textures, gb->textures); + gb->num_textures = 0; + + for (i = 0; i < gb->num_images; i++) { + gr->destroy_image(gr->egl_display, gb->images[i]); + gb->images[i] = NULL; + } + gb->num_images = 0; + + wl_array_for_each(color_egl_image, &gb->reimported_egl_images) + gr->destroy_image(gr->egl_display, color_egl_image->image); + wl_array_release(&gb->reimported_egl_images); + wl_array_init(&gb->reimported_egl_images); + gb->active_reimported_egl_image = NULL; + } + } + wl_list_for_each_safe(format, next_format, &gr->dmabuf_formats, link) dmabuf_format_destroy(format); weston_drm_format_array_fini(&gr->supported_dmabuf_formats); free(gr->supported_rendering_formats); + gr->supported_rendering_formats = NULL; + gr->supported_rendering_formats_count = 0; - gl_renderer_allocator_destroy(gr->allocator); + gr->base.dmabuf_alloc = NULL; + gr->base.import_dmabuf = NULL; + gr->base.get_supported_dmabuf_formats = NULL; + gr->base.create_renderbuffer_dmabuf = NULL; eglTerminate(gr->egl_display); eglReleaseThread(); +} + +static void +gl_renderer_destroy(struct weston_compositor *ec) +{ + struct gl_renderer *gr = get_renderer(ec); + + if (gr->recovering) { + gl_renderer_destroy_context(ec); + return; + } + + wl_signal_emit(&gr->destroy_signal, gr); + + gl_renderer_destroy_context(ec); + + gl_renderer_allocator_destroy(gr->allocator); + gr->allocator = NULL; wl_array_release(&gr->position_stream); wl_array_release(&gr->barycentric_stream); @@ -5247,57 +5383,200 @@ create_default_dmabuf_feedback(struct weston_compositor *ec, } static int -gl_renderer_display_create(struct weston_compositor *ec, - const struct gl_renderer_display_options *options) +gl_renderer_recover_resources(struct weston_compositor *ec) { - struct gl_renderer *gr; - const struct pixel_format_info *info; - int ret, nformats, i, j; - bool supported; + struct gl_renderer *gr = get_renderer(ec); + struct gl_buffer_state *gb, *tmp; + struct weston_output *output; + struct wl_list tmp_gb_list; - gr = zalloc(sizeof *gr); - if (gr == NULL) - return -1; + 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); + + /* Restore dma_bufs. */ + wl_list_init(&tmp_gb_list); + wl_list_for_each_safe(gb, tmp, &gr->dma_bufs, link) { +#define BUFFER_RECREATE() do { \ + destroy_buffer_state(gb); \ + new_gb = import_dmabuf(gr, dmabuf); \ + if (!new_gb) \ + return -EINVAL; \ + } while (0) +#define BUFFER_REATTACH() do { \ + linux_dmabuf_buffer_set_user_data(dmabuf, NULL, NULL); \ + buffer->renderer_private = new_gb; \ + new_gb->destroy_listener.notify = handle_buffer_destroy; \ + wl_signal_add(&buffer->destroy_signal, &new_gb->destroy_listener); \ + } while (0) + struct weston_buffer *buffer = gb->saved_buffer; + struct linux_dmabuf_buffer *dmabuf = gb->saved_dmabuf; + struct gl_surface_state *gs = gb->saved_gs; + struct gl_buffer_state *new_gb; + bool surface_bound = false; + + /* + * dma-buf ownership can live in three places: + * 1, Imported-only: linux_dmabuf_buffer userdata still owns gb. + * 2, Buffer-owned: weston_buffer::renderer_private owns gb. + * 3, Surface-bound: a live gl_surface_state still points at gb. + */ + if (dmabuf) { + /* 1, Imported-only state */ + void *user_data = + linux_dmabuf_buffer_get_user_data(dmabuf); + + /* Stale imported state, no longer owned by the dmabuf. */ + if (user_data != gb) { + destroy_buffer_state(gb); + continue; + } + + linux_dmabuf_buffer_set_user_data(dmabuf, NULL, NULL); + BUFFER_RECREATE(); + linux_dmabuf_buffer_set_user_data(dmabuf, new_gb, + gl_renderer_destroy_dmabuf); + new_gb->saved_dmabuf = dmabuf; + } else { + /* 2, Buffer-owned state */ + + /* Stale buffer-owned state. */ + if (!buffer || buffer->renderer_private != gb) { + destroy_buffer_state(gb); + continue; + } + + dmabuf = buffer->dmabuf; + if (!dmabuf) { + /* The buffer no longer has a live dma-buf backing. */ + destroy_buffer_state(gb); + continue; + } + + if (gs && + gs->surface && + gs->surface->renderer_state == gs && + gs->buffer == gb && + gs->buffer_ref.buffer == buffer) + surface_bound = true; + + BUFFER_RECREATE(); + BUFFER_REATTACH(); + new_gb->saved_gs = NULL; + new_gb->saved_dmabuf = NULL; + new_gb->saved_buffer = buffer; + + /* 3, Surface-bound state */ + if (surface_bound) + gl_renderer_attach_buffer(gs->surface, buffer); + } + + wl_list_insert(&tmp_gb_list, &new_gb->link); +#undef BUFFER_RECREATE +#undef BUFFER_REATTACH + } + + /* Manually add the new gbs to dma_bufs. */ + wl_list_insert_list(&gr->dma_bufs, &tmp_gb_list); + + /* + * Since all the buffer states have been recreated, mark them all as + * dirty to avoid garbage caused by original damage information. + */ + wl_list_for_each(output, &ec->output_list, link) { + struct weston_paint_node *pnode; + + wl_list_for_each(pnode, &output->paint_node_z_order_list, + z_order_link) { + struct weston_surface *surface = pnode->surface; + struct weston_buffer *buffer = surface->buffer_ref.buffer; + + if (!buffer || buffer->type != WESTON_BUFFER_SHM) + continue; + + pixman_region32_t region; + + pixman_region32_init_rect(®ion, 0, 0, + buffer->width, + buffer->height); + pixman_region32_copy(&surface->damage, ®ion); + ec->renderer->flush_damage(pnode); + pixman_region32_fini(®ion); + } + } + + return 0; +} + +static int +gl_renderer_init_context(struct weston_compositor *ec, + const struct gl_renderer_display_options *options) +{ + struct gl_renderer *gr = get_renderer(ec); + int ret; - gr->compositor = ec; - wl_list_init(&gr->shader_list); gr->platform = options->egl_platform; - - gr->extensions_scope = weston_compositor_add_log_scope(ec, "gl-renderer-ext", - "Print GL-renderer extensions\n", NULL, NULL, gr); - gr->paint_node_scope = weston_compositor_add_log_scope(ec, "gl-renderer-paint-nodes", - "Print GL-renderer debug information about paint nodes\n", NULL, NULL, gr); - gr->shader_scope = gl_shader_scope_create(gr); - - if (gl_renderer_setup_egl_client_extensions(gr) < 0) - goto fail; - - gr->base.repaint_output = gl_renderer_repaint_output; - gr->base.resize_output = gl_renderer_resize_output; - gr->base.create_renderbuffer = gl_renderer_create_renderbuffer; - gr->base.destroy_renderbuffer = gl_renderer_destroy_renderbuffer; - gr->base.flush_damage = gl_renderer_flush_damage; - gr->base.attach = gl_renderer_attach; - gr->base.destroy = gl_renderer_destroy; - gr->base.surface_copy_content = gl_renderer_surface_copy_content; - gr->base.fill_buffer_info = gl_renderer_fill_buffer_info; - gr->base.buffer_init = gl_renderer_buffer_init; - gr->base.output_set_border = gl_renderer_output_set_border; - gr->base.type = WESTON_RENDERER_GL; + gr->egl_device_extensions = 0; + gr->egl_display_extensions = 0; + gr->gl_extensions = 0; + gr->features = 0; + gr->get_graphics_reset_status = NULL; + gr->supported_rendering_formats = NULL; + gr->supported_rendering_formats_count = 0; + gr->base.dmabuf_alloc = NULL; + gr->base.import_dmabuf = NULL; + gr->base.get_supported_dmabuf_formats = NULL; + gr->base.create_renderbuffer_dmabuf = NULL; if (gl_renderer_setup_egl_display(gr, options->egl_native_display) < 0) goto fail; - gr->allocator = gl_renderer_allocator_create(gr, options); - if (!gr->allocator) - weston_log("failed to initialize allocator\n"); - weston_drm_format_array_init(&gr->supported_dmabuf_formats); log_egl_info(gr, gr->egl_display); - ec->renderer = &gr->base; - if (gl_renderer_setup_egl_extensions(ec) < 0) goto fail_with_error; @@ -5362,7 +5641,92 @@ gl_renderer_display_create(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: + gl_renderer_print_egl_error_state(); + if (gr->drm_device) { + weston_dmabuf_feedback_destroy(ec->default_dmabuf_feedback); + ec->default_dmabuf_feedback = NULL; + } +fail_feedback: + if (gr->drm_device) { + weston_dmabuf_feedback_format_table_destroy(ec->dmabuf_feedback_format_table); + ec->dmabuf_feedback_format_table = NULL; + } +fail_terminate: + free(gr->supported_rendering_formats); + gr->supported_rendering_formats = NULL; + gr->supported_rendering_formats_count = 0; + weston_drm_format_array_fini(&gr->supported_dmabuf_formats); + gr->base.dmabuf_alloc = NULL; + gr->base.import_dmabuf = NULL; + gr->base.get_supported_dmabuf_formats = NULL; + gr->base.create_renderbuffer_dmabuf = NULL; + eglTerminate(gr->egl_display); +fail: + return -1; +} + +static int +gl_renderer_display_create(struct weston_compositor *ec, + const struct gl_renderer_display_options *options) +{ + struct gl_renderer *gr = get_renderer(ec); + const struct pixel_format_info *info; + int nformats, i, j; + bool supported; + + if (gr && gr->recovering) + return gl_renderer_init_context(ec, options); + + gr = zalloc(sizeof *gr); + if (gr == NULL) + return -1; + + gr->compositor = ec; + wl_list_init(&gr->shader_list); + gr->platform = options->egl_platform; + + gr->extensions_scope = weston_compositor_add_log_scope(ec, "gl-renderer-ext", + "Print GL-renderer extensions\n", NULL, NULL, gr); + gr->paint_node_scope = weston_compositor_add_log_scope(ec, "gl-renderer-paint-nodes", + "Print GL-renderer debug information about paint nodes\n", NULL, NULL, gr); + gr->shader_scope = gl_shader_scope_create(gr); + + if (gl_renderer_setup_egl_client_extensions(gr) < 0) + goto fail; + + gr->base.repaint_output = gl_renderer_repaint_output; + gr->base.resize_output = gl_renderer_resize_output; + gr->base.create_renderbuffer = gl_renderer_create_renderbuffer; + gr->base.destroy_renderbuffer = gl_renderer_destroy_renderbuffer; + gr->base.flush_damage = gl_renderer_flush_damage; + gr->base.attach = gl_renderer_attach; + gr->base.destroy = gl_renderer_destroy; + gr->base.surface_copy_content = gl_renderer_surface_copy_content; + gr->base.fill_buffer_info = gl_renderer_fill_buffer_info; + gr->base.buffer_init = gl_renderer_buffer_init; + gr->base.output_set_border = gl_renderer_output_set_border; + gr->base.type = WESTON_RENDERER_GL; + + ec->renderer = &gr->base; + wl_signal_init(&gr->destroy_signal); + wl_list_init(&gr->dma_bufs); + wl_list_init(&gr->shm_bufs); + + if (gl_renderer_init_context(ec, options) < 0) + goto fail_context; + + gr->allocator = gl_renderer_allocator_create(gr, options); + if (!gr->allocator) + weston_log("failed to initialize allocator\n"); + else + gr->base.dmabuf_alloc = gl_renderer_dmabuf_alloc; /* Register supported wl_shm RGB formats. */ nformats = pixel_format_get_info_count(); @@ -5416,21 +5780,7 @@ gl_renderer_display_create(struct weston_compositor *ec, return 0; -fail_with_error: - gl_renderer_print_egl_error_state(); - if (gr->drm_device) { - weston_dmabuf_feedback_destroy(ec->default_dmabuf_feedback); - ec->default_dmabuf_feedback = NULL; - } -fail_feedback: - if (gr->drm_device) { - weston_dmabuf_feedback_format_table_destroy(ec->dmabuf_feedback_format_table); - ec->dmabuf_feedback_format_table = NULL; - } -fail_terminate: - free(gr->supported_rendering_formats); - weston_drm_format_array_fini(&gr->supported_dmabuf_formats); - eglTerminate(gr->egl_display); +fail_context: fail: weston_log_scope_destroy(gr->shader_scope); weston_log_scope_destroy(gr->extensions_scope); @@ -5510,6 +5860,12 @@ gl_renderer_setup(struct weston_compositor *ec) context_attribs[nattr++] = EGL_CONTEXT_PRIORITY_HIGH_IMG; } + if (egl_display_has(gr, EXTENSION_EXT_CREATE_CONTEXT_ROBUSTNESS)) { + context_attribs[nattr++] = + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR; + context_attribs[nattr++] = EGL_LOSE_CONTEXT_ON_RESET_KHR; + } + assert(nattr < ARRAY_LENGTH(context_attribs)); context_attribs[nattr] = EGL_NONE; @@ -5571,6 +5927,18 @@ gl_renderer_setup(struct weston_compositor *ec) return -1; } + if (gl_extensions_has(gr, EXTENSION_EXT_ROBUSTNESS)) { + GET_PROC_ADDRESS(gr->get_graphics_reset_status, + "glGetGraphicsResetStatusEXT"); + if (egl_display_has(gr, EXTENSION_EXT_CREATE_CONTEXT_ROBUSTNESS)) { + GLint strategy = 0; + + glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_EXT, &strategy); + if (strategy == GL_LOSE_CONTEXT_ON_RESET_EXT) + gr->features |= FEATURE_GRAPHICS_RESET_RECOVERY; + } + } + if (gl_extensions_has(gr, EXTENSION_OES_EGL_IMAGE)) { GET_PROC_ADDRESS(gr->image_target_texture_2d, "glEGLImageTargetTexture2DOES"); @@ -5751,15 +6119,26 @@ gl_renderer_setup(struct weston_compositor *ec) gl_extensions_has(gr, EXTENSION_OES_REQUIRED_INTERNALFORMAT))); weston_log_continue(STAMP_SPACE "In-shader blending: %s\n", yesno(gl_features_has(gr, FEATURE_SHADER_BLENDING))); + weston_log_continue(STAMP_SPACE "Graphics reset recovery: %s\n", + yesno(gl_features_has(gr, FEATURE_GRAPHICS_RESET_RECOVERY))); return 0; } +static void +gl_renderer_set_recovering(struct weston_compositor *ec, bool recovering) +{ + struct gl_renderer *gr = get_renderer(ec); + + gr->recovering = recovering; +} + WL_EXPORT struct gl_renderer_interface gl_renderer_interface = { .display_create = gl_renderer_display_create, .output_window_create = gl_renderer_output_window_create, .get_supported_rendering_formats = gl_renderer_get_supported_rendering_formats, .output_fbo_create = gl_renderer_output_fbo_create, .output_destroy = gl_renderer_output_destroy, + .set_recovering = gl_renderer_set_recovering, .create_fence_fd = gl_renderer_create_fence_fd, }; diff --git a/libweston/renderer-gl/gl-renderer.h b/libweston/renderer-gl/gl-renderer.h index 2afb9a953..689f43f58 100644 --- a/libweston/renderer-gl/gl-renderer.h +++ b/libweston/renderer-gl/gl-renderer.h @@ -184,6 +184,8 @@ struct gl_renderer_interface { void (*output_destroy)(struct weston_output *output); + void (*set_recovering)(struct weston_compositor *ec, bool recovering); + /* Create fence sync FD to wait for GPU rendering. * * Return FD on success, -1 on failure or unsupported diff --git a/libweston/renderer-vulkan/vulkan-renderer.c b/libweston/renderer-vulkan/vulkan-renderer.c index 5d95858b8..2ad76943a 100644 --- a/libweston/renderer-vulkan/vulkan-renderer.c +++ b/libweston/renderer-vulkan/vulkan-renderer.c @@ -2395,7 +2395,7 @@ vulkan_renderer_recreate_swapchain(struct weston_output *output, vulkan_renderer_create_swapchain(output, fb_size); } -static void +static enum weston_renderer_error vulkan_renderer_repaint_output(struct weston_output *output, pixman_region32_t *output_damage, weston_renderbuffer_t renderbuffer) @@ -2665,6 +2665,8 @@ vulkan_renderer_repaint_output(struct weston_output *output, pixman_region32_clear(&rb->damage); vo->frame_index = (vo->frame_index + 1) % vo->num_frames; + + return WESTON_RENDERER_ERROR_NONE; } static void