Table of Contents
- Errors
- A Vulkan command failed: result-error
- The system cannot do it: unsupported-error
- A struct field got a wrong value: struct-value-error
- Object lifetimes: destroyed-object-error, live-children-error
- A raw command is not available: command-unavailable
- Malformed arguments
- Validation messages are not conditions
Errors
Every error cl-vk signals is a vk-error, and each says what went wrong
and what to do about it. They fall into four groups, beside the
type-error of an argument of the wrong type.
error
├─ vk-error
│ ├─ result-error a Vulkan command failed
│ │ ├─ out-of-date-error
│ │ ├─ surface-lost-error
│ │ └─ device-lost-error
│ ├─ unsupported-error the system cannot do what was asked
│ ├─ struct-value-error a struct field got a value it cannot hold
│ ├─ destroyed-object-error an object was used after being destroyed
│ ├─ live-children-error an object was destroyed before its children
│ └─ (vk-error itself) misuse no other condition names
├─ type-error an argument of the wrong type
└─ vk-ffi:command-unavailable a raw command the instance or device lacks
A Vulkan command failed: result-error
Vulkan commands return a VkResult; a negative one is a failure. cl-vk
checks the result of every command it calls, and check does the same
for raw commands you call. The error names the command and explains the
result:
vkQueueSubmit failed with VK_ERROR_DEVICE_LOST: the device was lost, through a
driver error, a GPU reset or a hang
result-error-result returns the result as a keyword, such as
:error-out-of-device-memory, and result-error-command the command's
name. Three results callers commonly handle have their own subtypes:
| Condition | Result | What to do |
|---|---|---|
out-of-date-error |
VK_ERROR_OUT_OF_DATE_KHR |
The swapchain no longer matches its surface: recreate it. |
surface-lost-error |
VK_ERROR_SURFACE_LOST_KHR |
The window is gone: destroy the swapchain and the surface. |
device-lost-error |
VK_ERROR_DEVICE_LOST |
Destroy everything made from the device, and the device, then start again. |
acquire-next-image and present do not signal for out-of-date
swapchains: that is part of normal operation, so they return
:out-of-date as a status instead. A raw vkAcquireNextImageKHR or
vkQueuePresentKHR passed to check does signal out-of-date-error.
Other common results:
| Result | Meaning |
|---|---|
:error-out-of-host-memory |
A host memory allocation failed. |
:error-out-of-device-memory |
A device memory allocation failed: free GPU memory or use less. |
:error-initialization-failed |
The driver could not initialize the object. |
:error-incompatible-driver |
No driver supports the Vulkan version asked for. |
:error-format-not-supported |
The format is not supported for this use. |
:error-native-window-in-use-khr |
The window already has a surface. |
:error-validation-failed |
A validation layer found an invalid use of the API. |
Results that report success are returned by check as keywords:
:success, :suboptimal-khr, :timeout, :not-ready, :incomplete
and so on.
The system cannot do it: unsupported-error
Creating an instance, device or swapchain checks the request against
what is installed first. Anything missing signals an unsupported-error
before any Vulkan object is created, so there is nothing to clean up:
The instance extension VK_KHR_no_such_thing is not available.
AVAILABLE-INSTANCE-EXTENSIONS lists the supported ones.
The layer VK_LAYER_KHRONOS_validation is not available. Install the Vulkan
validation layers (on Debian and Ubuntu, the package vulkan-validationlayers),
or create the instance without :VALIDATION.
#<PHYSICAL-DEVICE "llvmpipe ..."> does not support these features:
physical-device-ray-tracing-motion-blur-features-nv :RAY-TRACING-MOTION-BLUR.
The surface does not support the present mode :IMMEDIATE. It supports :MAILBOX, :FIFO.
A swapchain needs the device extension VK_KHR_swapchain; create the device with
it in :EXTENSIONS.
unsupported-error-missing lists what is missing, for a program that
falls back:
(handler-case (vk:create-swapchain device surface :present-mode :mailbox)
(vk:unsupported-error ()
(vk:create-swapchain device surface :present-mode :fifo)))
It is signalled for: a Vulkan version the loader does not support; a missing layer, instance extension or device extension; a missing feature; a queue family that does not exist or has too few queues; a format, present mode, image count or image usage the surface does not support; and a surface no queue of the device can present to.
A struct field got a wrong value: struct-value-error
Filling a struct with a value of the wrong kind signals a
struct-value-error naming the struct, the field, the value and what
the field takes:
"linear" is not a valid value for the field :MAG-FILTER of VKS:SAMPLER-CREATE-INFO:
expected a keyword or an integer.
(1) is not a valid value for the field :WAIT-SEMAPHORE-INFOS of VKS:SUBMIT-INFO2:
expected a foreign pointer: SET-STRUCT does not allocate; use WITH-STRUCTS for lists.
Mistakes the macros can see when they expand (an unknown field, a
constant keyword that names no value, a field given twice) are vk-error
conditions at compile time instead, listing what is valid. See
Structs.
Object lifetimes: destroyed-object-error, live-children-error
Using an object after it was destroyed, or destroying it twice, signals
destroyed-object-error instead of passing a dangling handle to the
driver:
#<DEVICE "llvmpipe (LLVM 21.1.8, 256 bits)" (destroyed)> has been destroyed and
cannot be used.
Destroying an object while objects made from it are alive signals
live-children-error and destroys nothing:
#<DEVICE "llvmpipe (LLVM 21.1.8, 256 bits)"> cannot be destroyed while these
objects made from it are alive: #<FENCE>. Destroy them first.
live-children-error-children lists them. See Lifetimes and
Threads.
A raw command is not available: command-unavailable
Calling a raw command that the instance or device does not provide,
because the API version or extension it belongs to was not enabled,
signals vk-ffi:command-unavailable instead of crashing:
vkCmdDrawMeshTasksEXT is not available: the device did not provide it. Enable
the API version or extension that provides it when creating the device.
vk-ffi:command-available-p asks first. This condition belongs to the raw
layer and is not a vk-error. See Raw FFI Layer.
Malformed arguments
Wrong argument types signal type-error. Every public function
declares the types of its arguments, which SBCL checks on entry, so a
constant of the wrong type is already a warning when the call is
compiled; the elements of a list are checked in the body: a queue
request that is not (FAMILY COUNT), or a feature request that is not
(STRUCT FIELD ...), among them. In the raw
layer, bit-field and (setf bit-field) do the same for a struct
without bit-fields, a field it has not or a value that does not fit, and
the error's expected type lists what is valid.
Misuse that types cannot express signals a vk-error whose message says
what to write instead: a queue family given twice to create-device, a
field that is not a feature, device-queue for a queue the device was
not created with, acquire-next-image with neither a semaphore nor a
fence, create-swapchain without an :extent for a surface that has no
size, or a struct name that names no Vulkan struct:
The queue family 0 is asked for twice; ask once, for all its queues.
ACQUIRE-NEXT-IMAGE needs a :SEMAPHORE or a :FENCE to signal when the image is ready.
Validation messages are not conditions
What the validation layer reports is queued, not signalled: Vulkan calls
the debug messenger from inside the driver, where unwinding is not
allowed. Read the messages with take-debug-messages; see Instances and
Validation.