hal/vulkan/tests.lisp
Keep this ownership test backend-free: queue maintenance sees a completed frontier without asking a Vulkan loader or device.
The cached production closure resumes at its failed native call.
From here no caller retains queue/device/resource access.
Native work, portable state, dependencies, and the retry closure are all queue-owned before the injected owner callback escapes.
Both planes share one generation state. A subset advances it for its absent sibling, so rejoining never repeats a timeline signal.
Reusing the same raw handle starts a fresh state generation.
Production installs both shared closures before any render-pass cache entries exist. The pass drain must therefore snapshot lazily.
The first attempt completes the idle call but cannot close admission while a ledger owner remains failed.
The next attempt reuses the completed wait, drains the barrier, closes admission, and stops at one native render-pass failure.
Model the wrapper being dropped here: its installed finalizer
owns the exact native progress sequence already advanced by
explicit destroy. Its own idle step is safe and runs once, then
retirement resumes at the failed pass rather than at semaphore.
A texture finalized in this post-vkDestroyDevice window still runs its non-device owner callback while guarded Vk calls skip.
Retrying that same durable finalizer closure resumes at the failed instance call without repeating its idle or device steps.
The millisecond SDL wait must wake before the fractional deadline.
An ordinary late wake does not move the cadence's original phase.
A long pause skips missed frames rather than replaying them.
Present 7 targeted 1.000 s but appeared one refresh later. Native scheduling catches up from the actual display beat, while the unrelated host animation prediction remains untouched.
Feedback for 7 may still be the newest result when frame 9 is queued. The queued target, not a cross-clock lateness estimate, owns cadence.
Frame 8 then misses its target by one whole refresh. That lateness is diagnostic feedback; it must not turn frame 9 into another 33 ms gap.
(format descriptor)Test whether two compatible scalars are equal.
(device formats &key depth-format (depth-store-op :discard))(device gpu-formats descriptor &optional depth-format
(depth-store-op :discard))Return the cached render pass for GPU-FORMATS and optional DEPTH-FORMAT. GPU-FORMATS is a list in fragment-output location order. A single keyword is accepted for callers predating multiple render targets.
Logical negation of one test or raw truth value.
Base class for instantiated GPU resources.
(object)Return a thunk performing OBJECT's native teardown, or NIL when OBJECT owns nothing to tear down. The closure captures only extracted native handles and the device wrapper, never OBJECT itself, so it can outlive OBJECT as its leak finalizer. Capturing the device wrapper also orders finalization: a device stays…
(&rest steps)Return a retryable closure over ordered, individually idempotent STEPS. Each zero-argument step is removed only after it returns normally. A retry therefore resumes at the failing native call without repeating any earlier destructive call which already succeeded.
(device handle &key semaphore semaphore-state (semaphore-value 0)
submitted owner (layout :general))How the children of a list are arranged.
(device handle &key resources textures final-layouts)Whether retaining a queue custodian starts eventual background service.
(resource device invalidate)Transfer RESOURCE's native ownership, then logically invalidate it. A live queue owns the retirement before INVALIDATE marks the wrapper and cancels its finalizer. Queue maintenance immediately attempts anything already safe and retains failures. Without a live queue, native teardown must succeed before INVALIDATE…
(queue)Retire live submissions the completion frontier has passed. Retiring a submission drops the queue's references to everything it retained. The independent retirement ledger then attempts every native teardown which that frontier makes safe; failures remain queue-owned.
(device owner teardown invalidate)Transfer OWNER's native teardown to DEVICE, then invalidate OWNER. Backend methods may transfer ownership to a durable device queue before INVALIDATE and attempt it immediately. The default has no such queue: native TEARDOWN must return successfully before INVALIDATE is called.
(queue buffers &key (wait-semaphores #()) (signal-semaphores #()))Submit BUFFERS through vkQueueSubmit2. WAIT-SEMAPHORES and SIGNAL-SEMAPHORES are sequences of semaphore submit entries as understood by FILL-SEMAPHORE-SUBMIT-INFOS.
(queue work)Schedule some command buffers on the QUEUE. Submission is asynchronous: returning does not mean the GPU has finished the work, only that the implementation retains everything the work depends on until it completes. Use SUBMITTED-WORK-DONE to wait.
()Service one registry snapshot without holding the registry lock. Returns true when any backend reports progress. Errors are diagnosed once per consecutive failure and never prevent later custodians from being serviced.
(ledger custodian)(queue semaphore initial-value)(queue state)GPU-RESOURCE-LEAKED conditions recorded for objects the collector had to reclaim. Inspect or clear this from the REPL to audit leak hygiene.
Signaled from the finalizer when a live GPU object is collected without DESTROY. The native resources are still reclaimed, but explicit destruction is the expected discipline.
(resource-class label device owner teardown)(handle)Logically invalidate HANDLE immediately. Native teardown may be deferred until submitted work which captured HANDLE has completed.
(command-buffer)(device command-pool)(encoder device command-buffer command-pool native-resources)(encoder)Arrange to warn about and reclaim ENCODER if it is collected while it still owns its command pool. FINISH and DESTROY transfer or release that ownership and cancel this finalizer.
(device)(device semaphore)(device render-pass)(device)(instance)(device queue)(ledger resource ready-after teardown)Transfer RESOURCE's native teardown to LEDGER and return its entry. The caller holds its queue lock. This append must happen before the public wrapper is marked destroyed or its leak finalizer is cancelled.
If you're lucky, someone has bound this to a working GPU-PROVIDER.
Multiplication and scalar scaling.
(pathname pixels width height format)Test whether one compatible scalar is less than another.
(frame-function &key (frames-per-second 60))A native destination with a lifetime and frame clock.
(clock canvas timestamp)Run any frame CLOCK has made due at TIMESTAMP; true if one ran.
(clock timestamp)Return milliseconds until CLOCK is due, or NIL to wait indefinitely.
The componentwise absolute value of a raw value.
Subtraction or unary negation.
Addition over compatible quantities.
Division of two represented quantities.
Test whether one compatible scalar is greater than another.
(&key (source #'monotonic-seconds))(clock)(clock timestamp function)(clock)(&key (title "luv canvas") (width 800) (height 600)
x y (visible-p t) (fullscreen-p nil)
(high-pixel-density-p nil)
(clock (make-demand-clock))
(time (make-lazy-clock))
(presentation-api :vulkan))Construct an unrealized SDL canvas. WIDTH or HEIGHT may be NIL, which asks the display for a size when the window is finally created.
(canvas)Predict when a frame acquired now will become visible on CANVAS.
(frame-function)(canvas condition)(canvas)(descriptor)(&key
(application-name "luv")
((:application-version application-version-value)
(make-version 0 0 1))
(engine-name "luv")
((:engine-version engine-version-value) (make-version 0 0 1))
;; Luv assumes modern Vulkan. Timeline semaphores and
;; synchronization2 are mandatory core features at this version.
((:api-version api-version-value) (make-version 1 4 0))
flags
enabled-extension-names)(device name)One swapchain's bounded, presentation-ID-indexed display observations.
(timeline present-id predicted-seconds submitted-seconds
&optional (target-nanoseconds 0))(timeline present-id actual-nanoseconds time-domain time-domain-id)(observations)(observations)(timeline fallback-time)Return FALLBACK-TIME and the next native display beat when available. The selected Vulkan time domain may be opaque and unrelated to Lisp's monotonic clock. Keep animation prediction in the host domain and advance native targets only from observed or already-scheduled native timestamps.
Convert one scalar float or unsigned value to a 32-bit float.
((trace) &body body)Run BODY with this thread's Vulkan calls recorded into a fresh trace. Binds the backend-local trace only for BODY's dynamic extent.
(trace)
Capture only the test's explicit state boxes, as a real Vulkan teardown captures raw handles rather than its public wrapper.