2 Instances and Validation
dxtr edited this page 2026-10-14 03:44:00 +02:00

Instances and Validation

An instance is the connection between your program and Vulkan. It holds the instance extensions and layers you enabled, and everything else is made from it.

Creating an instance

(vk:with-instance (instance :application-name "my game"
                            :extensions '("VK_KHR_surface" "VK_KHR_wayland_surface"))
  ...)

with-instance calls create-instance with its arguments, binds the instance, and destroys it when the body is left, normally or not. When the instance must outlive a dynamic extent, call create-instance and destroy-instance yourself.

create-instance takes these keyword arguments:

Argument Default Meaning
:api-version '(1 4) The Vulkan version to use, a list (MAJOR MINOR).
:extensions '() Instance extensions to enable, by name.
:layers '() Layers to enable, by name.
:validation nil When true, enable the Khronos validation layer and queue its messages.
:validation-checks '() Extra validation checks, :synchronization and :best-practices. Turns validation on.
:application-name "" Passed to drivers, which may use it to apply per-application fixes.
:application-version 0 Likewise, an integer.
:engine-name "cl-vk" Likewise.
:engine-version 0 Likewise, an integer.

Before creating anything, create-instance checks the request against what is installed. If the loader does not support :api-version, or a layer or extension is not available, it signals an unsupported-error that names what is missing and says what to do:

(handler-case (vk:create-instance :extensions '("VK_KHR_no_such_thing"))
  (vk:unsupported-error (e)
    (list (princ-to-string e) (vk:unsupported-error-missing e))))
;; => ("The instance extension VK_KHR_no_such_thing is not available.
;;      AVAILABLE-INSTANCE-EXTENSIONS lists the supported ones."
;;     ("VK_KHR_no_such_thing"))

Which extensions?

To present to a window, enable "VK_KHR_surface" and the surface extension of the window system:

Window system Extension
Wayland "VK_KHR_wayland_surface"
Windows "VK_KHR_win32_surface"
X11 (xcb) "VK_KHR_xcb_surface"
X11 (Xlib) "VK_KHR_xlib_surface"
none, for tests "VK_EXT_headless_surface"

Usually the library that owns the window says which extensions it needs. available-instance-extensions lists what the loader and drivers provide; given a layer's name, it lists what that layer provides.

Asking about the instance

Function Returns
instance-api-version The version asked for, as (MAJOR MINOR PATCH).
instance-extensions The extension names enabled, those validation added included.
instance-layers The layer names enabled, likewise.

Validation

The Khronos validation layer checks every call against the Vulkan specification and reports what is wrong: a missing barrier, a wrong image layout, a struct member out of range. Use it during development. It needs the validation layers installed (vulkan-validationlayers on Debian and Ubuntu); without them, :validation t signals an unsupported-error that says so.

(vk:with-instance (instance :validation t)
  ;; ... create devices, record and submit work ...
  (dolist (message (vk:take-debug-messages instance))
    (when (eq (vk:debug-message-severity message) :error)
      (format *error-output* "~&~A: ~A~%"
              (vk:debug-message-id-name message)
              (vk:debug-message-text message)))))

With :validation t, cl-vk enables the layer and the extension VK_EXT_debug_utils, and installs a debug messenger. The messenger receives messages on whatever thread the driver calls it from, queues them, and returns at once; it never signals into the driver. take-debug-messages returns the messages queued since the last call, oldest first, and forgets them. Messages from creating the instance itself are included.

A debug-message has:

Reader Value
debug-message-severity :verbose, :info, :warning or :error
debug-message-types a list of :general, :validation and :performance
debug-message-text the message, a string
debug-message-id-name the name of the check, such as "SYNC-HAZARD-WRITE-AFTER-READ", or nil

All severities are queued, :verbose and :info included, so filter by severity. Call take-debug-messages regularly, once a frame for example: the queue is not bounded.

A test can make validation part of the check, as cl-vk's own tests do:

(defun validation-errors (instance)
  (mapcar #'vk:debug-message-text
          (remove :error (vk:take-debug-messages instance)
                  :key #'vk:debug-message-severity :test-not #'eq)))

Extra validation checks

Some checks are off in the layer by default because they are slow. :validation-checks turns them on, and turns validation on with them:

  • :synchronization checks the barriers and semaphores between commands that use the same memory, shader accesses through descriptors included. It finds the hazards that cause flickering or corruption on one GPU and not another.
  • :best-practices reports uses that are valid but slow or fragile.
(vk:with-instance (instance :extensions '("VK_KHR_surface" "VK_EXT_headless_surface")
                            :validation-checks '(:synchronization))
  ...)

These need VK_EXT_layer_settings, which recent validation layers provide; cl-vk enables it.

Destroying an instance

destroy-instance destroys the instance and its debug messenger. Every device and surface made from it must be destroyed first; otherwise it signals live-children-error and destroys nothing. Using an instance after it is destroyed signals destroyed-object-error.

Thread rules

An instance may be used from several threads at once, but creating and destroying the objects made from it must happen on one thread at a time, and it must not be destroyed while another thread uses it. take-debug-messages may be called from any thread.