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 <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2022-02-08 07:53:15 +00:00 committed by yshui
parent 126750f099
commit a383dc1cdd
5 changed files with 45 additions and 10 deletions

View File

@ -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[];

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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

View File

@ -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;