Table of Contents
Vulkan Surfaces
The optional system cl-windowing/vulkan creates Vulkan surfaces for
windows, through cl-vk. The rest of
cl-windowing never depends on Vulkan.
If you draw with cl-gfx, you do not need this page: cl-gfx/windowing
uses cl-windowing/vulkan for you.
Creating a surface
(asdf:load-system :cl-windowing/wayland) ; on Windows, :cl-windowing/win32
(asdf:load-system :cl-windowing/vulkan)
(win:with-window-system (window-system)
(win:with-window (window window-system :title "Vulkan")
(vk:with-instance (instance :extensions (cl-windowing/vulkan:vulkan-instance-extensions
window-system))
(let ((surface (cl-windowing/vulkan:create-vulkan-surface window instance)))
;; Create a device and a swapchain for SURFACE, and draw.
(vk:destroy-surface surface)))))
Two functions:
(cl-windowing/vulkan:vulkan-instance-extensions window-system) => list of strings
(cl-windowing/vulkan:create-vulkan-surface window instance) => cl-vk:surface
vulkan-instance-extensionsnames the instance extensions that surfaces of the window system need. On Wayland:("VK_KHR_surface" "VK_KHR_wayland_surface"); on Windows:("VK_KHR_surface" "VK_KHR_win32_surface"). Pass them, with any others you need, as the instance's:extensions.create-vulkan-surfacecreates a surface for a window, and returns it as acl-vk:surface, which you then own. It may be called before the window has its first size.
If the instance lacks an extension, create-vulkan-surface signals
cl-vk:unsupported-error, and says what to do:
A Vulkan surface for #<WAYLAND-WINDOW "Vulkan" 800x600> needs the instance
extensions VK_KHR_surface, VK_KHR_wayland_surface; create the instance with
(CL-WINDOWING/VULKAN:VULKAN-INSTANCE-EXTENSIONS #<WAYLAND-WINDOW-SYSTEM
wayland>) in :EXTENSIONS.
For a destroyed window, it signals closed-error.
Destroying
Destroy the surface with cl-vk:destroy-surface before the window,
after destroying its swapchain. A surface that outlives its window refers
to a native window that no longer exists.
Sizing the swapchain
On Wayland a surface has no size of its own: the swapchain decides it. On
Windows the surface has a size of its own, the window's client area, which
can differ from window-pixel-size by a pixel at a fractional scale; cl-vk's
create-swapchain takes that size where a surface has one, so read the
swapchain's size back with vk:swapchain-extent. Size it by the window's
size in pixels, and follow the
resize handshake:
- Wait until
window-configured-pis true. Until then nothing may be presented, andwindow-pixel-sizeis 0 by 0. See Window Systems and Windows. - Create the swapchain at
window-pixel-size. - Each frame, check
window-pending-pixel-size. When it returns a size that differs from the swapchain's, recreate the swapchain at that size. - Draw the frame.
- If a size was pending, call
adopt-window-sizejust before presenting. - Present.
An outline with cl-vk, once the window is configured:
(defun swapchain-extent (window)
(multiple-value-list (win:window-pixel-size window)))
(let ((swapchain (vk:create-swapchain device surface :extent (swapchain-extent window))))
(loop
(let ((adopt nil))
(multiple-value-bind (width height) (win:window-pending-pixel-size window)
(when width
(setf adopt t)
(unless (equal (vk:swapchain-extent swapchain) (list width height))
;; After the device has finished with the old images.
(setf swapchain (vk:recreate-swapchain swapchain :extent (list width height))))))
;; Acquire an image with vk:acquire-next-image, record and submit.
(when adopt
(win:adopt-window-size window))
;; Present with vk:present. On :out-of-date, recreate the swapchain
;; at (swapchain-extent window).
)))
Threads
create-vulkan-surface may be called from any thread. The surface and the
swapchain follow cl-vk's thread rules, and usually belong to the render
thread. See Threads.
How it works
A backend says what a surface for a window is made from, through the
backend functions backend-vulkan-extensions and backend-vulkan-target.
cl-windowing/vulkan makes the VkSurfaceKHR from that and hands it to
cl-vk with cl-vk:adopt-surface. Native pointers, such as the
wl_display and the wl_surface, or the module and window handles on
Windows, cross between the libraries only there.
See Backend Protocol.