llvmpipe: Implement manual context resets

Make it possible to trigger a emulated GPU reset by creating a file at
the path of the `LP_CONTEXT_RESET_FILE` env var. All llvmpipe contexts
using the `LOSE_CONTEXT_ON_RESET` strategy that where created before
the that file will start returning `PIPE_UNKNOWN_CONTEXT_RESET` in
`get_device_reset_status()`, while newer contexts - most notably those
created by apps in reaction to the device reset - continue to return
`PIPE_NO_RESET`.

Note that, because we're dealing with files, rtime is used instead of
mtime as the later

Usage:
```
LP_CONTEXT_RESET_FILE=~/llvmpipe_reset LIBGL_ALWAYS_SOFTWARE=1
someapp
touch ~/llvmpipe_reset
```

Signed-off-by: Robert Mader <robert.mader@collabora.com>
Reviewed-By: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40681>
This commit is contained in:
Robert Mader 2026-03-27 14:56:46 +01:00 committed by Marge Bot
parent c32015da05
commit e68a0dfb12
3 changed files with 70 additions and 0 deletions

View file

@ -1356,6 +1356,14 @@ LLVMpipe driver environment variables
turns off threading completely. The default value is the number of
CPU cores present.
.. envvar:: LP_CONTEXT_RESET_FILE
a file path. If set, contexts using the LOSE_CONTEXT_ON_RESET strategy will
check it for the presence and modification time of a file and trigger an
emulated device reset if they were created before the last modification time.
Currently not available on Windows.
VMware SVGA driver environment variables
----------------------------------------

View file

@ -30,6 +30,8 @@
* Keith Whitwell <keithw@vmware.com>
*/
#include <sys/stat.h>
#include "draw/draw_context.h"
#include "draw/draw_vbuf.h"
#include "pipe/p_defines.h"
@ -194,6 +196,45 @@ lp_draw_disk_cache_insert_shader(void *cookie,
static enum pipe_reset_status
llvmpipe_get_device_reset_status(struct pipe_context *pipe)
{
#if !DETECT_OS_WINDOWS
struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
struct stat st_reset_file;
struct timespec ts_now;
int64_t now_ns;
if (!(llvmpipe->flags & PIPE_CONTEXT_LOSE_CONTEXT_ON_RESET) ||
llvmpipe->context_reset_file_path == NULL)
return PIPE_NO_RESET;
clock_gettime(CLOCK_REALTIME, &ts_now);
now_ns = (int64_t)ts_now.tv_sec * 1000000000LL + ts_now.tv_nsec;
/*
* Only return a *RESET* status for ~0.5 milliseconds. From the spec:
*
* 5. How should the application react to a reset context event?
*
* RESOLVED: For this extension, the application is expected to query
* the reset status until NO_ERROR is returned. If a reset is encountered,
* at least one *RESET* status will be returned. Once NO_ERROR is again
* encountered, the application can safely destroy the old context and
* create a new one.
*/
if (llvmpipe->context_reset_time_ns > 0)
return now_ns - llvmpipe->context_reset_time_ns < 500000 ?
PIPE_UNKNOWN_CONTEXT_RESET : PIPE_NO_RESET;
if (stat(llvmpipe->context_reset_file_path, &st_reset_file) == 0) {
int64_t file_mod_time_ns = (int64_t)st_reset_file.st_mtim.tv_sec *
1000000000LL + st_reset_file.st_mtim.tv_nsec;
if (llvmpipe->context_creation_time_ns < file_mod_time_ns) {
llvmpipe->context_reset_time_ns = now_ns;
return PIPE_UNKNOWN_CONTEXT_RESET;
}
}
#endif
return PIPE_NO_RESET;
}
@ -214,6 +255,20 @@ llvmpipe_create_context(struct pipe_screen *screen, void *priv,
memset(llvmpipe, 0, sizeof *llvmpipe);
llvmpipe->flags = flags;
#if !DETECT_OS_WINDOWS
llvmpipe->context_reset_file_path =
os_get_option_secure("LP_CONTEXT_RESET_FILE");
if (llvmpipe->flags & PIPE_CONTEXT_LOSE_CONTEXT_ON_RESET &&
llvmpipe->context_reset_file_path != NULL) {
struct timespec ts_now;
clock_gettime(CLOCK_REALTIME, &ts_now);
llvmpipe->context_creation_time_ns =
(int64_t)ts_now.tv_sec * 1000000000LL + ts_now.tv_nsec;
}
#endif
list_inithead(&llvmpipe->fs_variants_list.list);
list_inithead(&llvmpipe->setup_variants_list.list);

View file

@ -59,6 +59,9 @@ struct lp_velems_state;
struct llvmpipe_context {
struct pipe_context pipe; /**< base class */
/** Context creation flags */
unsigned flags;
struct list_head list;
/** Constant state objects */
const struct pipe_blend_state *blend;
@ -197,6 +200,10 @@ struct llvmpipe_context {
int max_global_buffers;
struct pipe_resource **global_buffers;
/** Used for context reset emulation, see LP_CONTEXT_RESET_FILE */
const char *context_reset_file_path;
int64_t context_creation_time_ns;
int64_t context_reset_time_ns;
};