diff --git a/src/backend/backend.h b/src/backend/backend.h index ed66442..3e742f2 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 0ed973b..d22636e 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 9bea831..7c2aaa3 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 54d1114..3af7c1b 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 1061f0b..44b4da0 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;