From a383dc1cddd2d3aa31cf42ff3d13720f162634e2 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Tue, 8 Feb 2022 07:53:15 +0000 Subject: [PATCH] backend: add new optional API: device_status This is meant to be used to detect GPU resets. Implemented in the glx backend using the GL_ARB_robustness extension. Signed-off-by: Yuxuan Shui --- src/backend/backend.h | 11 +++++++++++ src/backend/gl/gl_common.c | 13 +++++++++++++ src/backend/gl/gl_common.h | 3 +++ src/backend/gl/glx.c | 27 +++++++++++++++++---------- src/backend/gl/glx.h | 1 + 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/backend/backend.h b/src/backend/backend.h index ed66442c..3e742f2a 100644 --- a/src/backend/backend.h +++ b/src/backend/backend.h @@ -32,6 +32,15 @@ typedef struct backend_base { typedef void (*backend_ready_callback_t)(void *); +// This mimics OpenGL's ARB_robustness extension, which enables detection of GPU context +// resets. +// See: https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_robustness.txt, section +// 2.6 "Graphics Reset Recovery". +enum device_status { + DEVICE_STATUS_NORMAL, + DEVICE_STATUS_RESETTING, +}; + // When image properties are actually applied to the image, they are applied in a // particular order: // @@ -273,6 +282,8 @@ struct backend_operations { enum driver (*detect_driver)(backend_t *backend_data); void (*diagnostics)(backend_t *backend_data); + + enum device_status (*device_status)(backend_t *backend_data); }; extern struct backend_operations *backend_list[]; diff --git a/src/backend/gl/gl_common.c b/src/backend/gl/gl_common.c index 0ed973bf..d22636e3 100644 --- a/src/backend/gl/gl_common.c +++ b/src/backend/gl/gl_common.c @@ -1694,6 +1694,7 @@ bool gl_init(struct gl_data *gd, session_t *ps) { } else { gd->is_nvidia = false; } + gd->has_robustness = gl_has_extension("GL_ARB_robustness"); return true; } @@ -1908,3 +1909,15 @@ bool gl_image_op(backend_t *base, enum image_operations op, void *image_data, return true; } + +enum device_status gl_device_status(backend_t *base) { + auto gd = (struct gl_data *)base; + if (!gd->has_robustness) { + return DEVICE_STATUS_NORMAL; + } + if (glGetGraphicsResetStatusARB() == GL_NO_ERROR) { + return DEVICE_STATUS_NORMAL; + } else { + return DEVICE_STATUS_RESETTING; + } +} diff --git a/src/backend/gl/gl_common.h b/src/backend/gl/gl_common.h index 9bea831d..7c2aaa3f 100644 --- a/src/backend/gl/gl_common.h +++ b/src/backend/gl/gl_common.h @@ -75,6 +75,8 @@ struct gl_data { backend_t base; // If we are using proprietary NVIDIA driver bool is_nvidia; + // If ARB_robustness extension is present + bool has_robustness; // Height and width of the root window int height, width; gl_win_shader_t win_shader; @@ -132,6 +134,7 @@ void gl_fill(backend_t *base, struct color, const region_t *clip); void gl_present(backend_t *base, const region_t *); bool gl_read_pixel(backend_t *base, void *image_data, int x, int y, struct color *output); +enum device_status gl_device_status(backend_t *base); static inline void gl_delete_texture(GLuint texture) { glDeleteTextures(1, &texture); diff --git a/src/backend/gl/glx.c b/src/backend/gl/glx.c index 54d1114f..3af7c1b3 100644 --- a/src/backend/gl/glx.c +++ b/src/backend/gl/glx.c @@ -302,16 +302,21 @@ static backend_t *glx_init(session_t *ps) { continue; } - gd->ctx = glXCreateContextAttribsARB(ps->dpy, cfg[i], 0, true, - (int[]){ - GLX_CONTEXT_MAJOR_VERSION_ARB, - 3, - GLX_CONTEXT_MINOR_VERSION_ARB, - 3, - GLX_CONTEXT_PROFILE_MASK_ARB, - GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 0, - }); + int *attributes = (int[]){GLX_CONTEXT_MAJOR_VERSION_ARB, + 3, + GLX_CONTEXT_MINOR_VERSION_ARB, + 3, + GLX_CONTEXT_PROFILE_MASK_ARB, + GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + 0, + 0, + 0}; + if (glxext.has_GLX_ARB_create_context_robustness) { + attributes[6] = GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB; + attributes[7] = GLX_LOSE_CONTEXT_ON_RESET_ARB; + } + + gd->ctx = glXCreateContextAttribsARB(ps->dpy, cfg[i], 0, true, attributes); free(cfg); if (!gd->ctx) { @@ -541,6 +546,7 @@ struct backend_operations glx_ops = { .destroy_blur_context = gl_destroy_blur_context, .get_blur_size = gl_get_blur_size, .diagnostics = glx_diagnostics, + .device_status = gl_device_status, .max_buffer_age = 5, // Why? }; @@ -608,6 +614,7 @@ void glxext_init(Display *dpy, int screen) { check_ext(GLX_EXT_texture_from_pixmap); check_ext(GLX_ARB_create_context); check_ext(GLX_EXT_buffer_age); + check_ext(GLX_ARB_create_context_robustness); #ifdef GLX_MESA_query_renderer check_ext(GLX_MESA_query_renderer); #endif diff --git a/src/backend/gl/glx.h b/src/backend/gl/glx.h index 1061f0bb..44b4da05 100644 --- a/src/backend/gl/glx.h +++ b/src/backend/gl/glx.h @@ -55,6 +55,7 @@ struct glxext_info { bool has_GLX_ARB_create_context; bool has_GLX_EXT_buffer_age; bool has_GLX_MESA_query_renderer; + bool has_GLX_ARB_create_context_robustness; }; extern struct glxext_info glxext;