diff --git a/docs/envvars.rst b/docs/envvars.rst index 1310ba3ee0b..9e90cad565b 100644 --- a/docs/envvars.rst +++ b/docs/envvars.rst @@ -189,6 +189,10 @@ Core Mesa environment variables overrides the WSI present mode clients specify in ``VkSwapchainCreateInfoKHR::presentMode``. Values can be ``fifo``, ``relaxed``, ``mailbox`` or ``immediate``. +:envvar:`MESA_VK_ABORT_ON_DEVICE_LOSS` + causes the Vulkan driver to call abort() immediately after detecting a + lost device. This is extremely useful when testing as it prevents the + test suite from continuing on with a lost device. :envvar:`MESA_LOADER_DRIVER_OVERRIDE` chooses a different driver binary such as ``etnaviv`` or ``zink``. diff --git a/src/vulkan/runtime/vk_device.c b/src/vulkan/runtime/vk_device.c index e3617507bae..13d674e22cd 100644 --- a/src/vulkan/runtime/vk_device.c +++ b/src/vulkan/runtime/vk_device.c @@ -29,6 +29,7 @@ #include "vk_physical_device.h" #include "vk_queue.h" #include "vk_util.h" +#include "util/debug.h" #include "util/hash_table.h" #include "util/ralloc.h" @@ -117,6 +118,45 @@ vk_device_finish(UNUSED struct vk_device *device) vk_object_base_finish(&device->base); } +void +_vk_device_report_lost(struct vk_device *device) +{ + assert(p_atomic_read(&device->_lost.lost) > 0); + + device->_lost.reported = true; + + vk_foreach_queue(queue, device) { + if (queue->_lost.lost) { + __vk_errorf(queue, VK_ERROR_DEVICE_LOST, + queue->_lost.error_file, queue->_lost.error_line, + "%s", queue->_lost.error_msg); + } + } +} + +VkResult +_vk_device_set_lost(struct vk_device *device, + const char *file, int line, + const char *msg, ...) +{ + /* This flushes out any per-queue device lost messages */ + if (vk_device_is_lost(device)) + return VK_ERROR_DEVICE_LOST; + + p_atomic_inc(&device->_lost.lost); + device->_lost.reported = true; + + va_list ap; + va_start(ap, msg); + __vk_errorv(device, VK_ERROR_DEVICE_LOST, file, line, msg, ap); + va_end(ap); + + if (env_var_as_boolean("MESA_VK_ABORT_ON_DEVICE_LOSS", false)) + abort(); + + return VK_ERROR_DEVICE_LOST; +} + PFN_vkVoidFunction vk_device_get_proc_addr(const struct vk_device *device, const char *name) diff --git a/src/vulkan/runtime/vk_device.h b/src/vulkan/runtime/vk_device.h index 3bb0347e018..d9da1fba3d8 100644 --- a/src/vulkan/runtime/vk_device.h +++ b/src/vulkan/runtime/vk_device.h @@ -28,6 +28,7 @@ #include "vk_object.h" #include "util/list.h" +#include "util/u_atomic.h" #ifdef __cplusplus extern "C" { @@ -47,6 +48,11 @@ struct vk_device { struct list_head queues; + struct { + int lost; + bool reported; + } _lost; + #ifdef ANDROID mtx_t swapchain_private_mtx; struct hash_table *swapchain_private; @@ -66,6 +72,31 @@ vk_device_init(struct vk_device *device, void vk_device_finish(struct vk_device *device); +VkResult PRINTFLIKE(4, 5) +_vk_device_set_lost(struct vk_device *device, + const char *file, int line, + const char *msg, ...); + +#define vk_device_set_lost(device, ...) \ + _vk_device_set_lost(device, __FILE__, __LINE__, __VA_ARGS__) + +void _vk_device_report_lost(struct vk_device *device); + +static inline bool +vk_device_is_lost_no_report(struct vk_device *device) +{ + return p_atomic_read(&device->_lost.lost) > 0; +} + +static inline bool +vk_device_is_lost(struct vk_device *device) +{ + int lost = vk_device_is_lost_no_report(device); + if (unlikely(lost && !device->_lost.reported)) + _vk_device_report_lost(device); + return lost; +} + PFN_vkVoidFunction vk_device_get_proc_addr(const struct vk_device *device, const char *name); diff --git a/src/vulkan/runtime/vk_queue.c b/src/vulkan/runtime/vk_queue.c index d1c0351ce35..7f4a5ce2043 100644 --- a/src/vulkan/runtime/vk_queue.c +++ b/src/vulkan/runtime/vk_queue.c @@ -23,6 +23,8 @@ #include "vk_queue.h" +#include "util/debug.h" + #include "vk_device.h" VkResult @@ -54,3 +56,30 @@ vk_queue_finish(struct vk_queue *queue) list_del(&queue->link); vk_object_base_finish(&queue->base); } + +VkResult +_vk_queue_set_lost(struct vk_queue *queue, + const char *file, int line, + const char *msg, ...) +{ + if (queue->_lost.lost) + return VK_ERROR_DEVICE_LOST; + + queue->_lost.lost = true; + queue->_lost.error_file = file; + queue->_lost.error_line = line; + + va_list ap; + va_start(ap, msg); + vsnprintf(queue->_lost.error_msg, sizeof(queue->_lost.error_msg), msg, ap); + va_end(ap); + + p_atomic_inc(&queue->base.device->_lost.lost); + + if (env_var_as_boolean("MESA_VK_ABORT_ON_DEVICE_LOSS", false)) { + _vk_device_report_lost(queue->base.device); + abort(); + } + + return VK_ERROR_DEVICE_LOST; +} diff --git a/src/vulkan/runtime/vk_queue.h b/src/vulkan/runtime/vk_queue.h index 1a63b1f9d80..7998a277c39 100644 --- a/src/vulkan/runtime/vk_queue.h +++ b/src/vulkan/runtime/vk_queue.h @@ -48,6 +48,14 @@ struct vk_queue { /* Which queue this is within the queue family */ uint32_t index_in_family; + struct { + /* Only set once atomically by the queue */ + int lost; + int error_line; + const char *error_file; + char error_msg[80]; + } _lost; + /** * VK_EXT_debug_utils * @@ -99,6 +107,20 @@ vk_queue_init(struct vk_queue *queue, struct vk_device *device, void vk_queue_finish(struct vk_queue *queue); +VkResult PRINTFLIKE(4, 5) +_vk_queue_set_lost(struct vk_queue *queue, + const char *file, int line, + const char *msg, ...); + +#define vk_queue_set_lost(queue, ...) \ + _vk_queue_set_lost(queue, __FILE__, __LINE__, __VA_ARGS__) + +static inline bool +vk_queue_is_lost(struct vk_queue *queue) +{ + return queue->_lost.lost; +} + #define vk_foreach_queue(queue, device) \ list_for_each_entry(struct vk_queue, queue, &(device)->queues, link)