hal/gpu.lisp
Base condition for errors exposed by the luv GPU API.
Base condition for an operation rejected by a GPU object.
Leaked GPU A~@[ labeled ~S]: it was reclaimed by the ~
garbage collector instead of being destroyed explicitly.
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.
One native teardown durably owned by a GPU queue.
READY-AFTER is the queue completion frontier which makes TEARDOWN safe. RESOURCE is retained for diagnosis and, for current backends, also supplies the native handles used by TEARDOWN.
Structured evidence that native GPU ownership could not be retired.
D native GPU retirement:P failed during ~S; ~
the retirement ledger retained the failed resource and its FIFO successors ~
for retry.
A queue-owned list of native teardowns, including failed attempts.
SBCL terminates and joins ephemeral threads while holding its private thread-creation lock. Tell the worker's unwind cleanup not to fight that orderly shutdown by trying to restart itself under the same lock.
Perform one safe eventual-retirement service pass for custodian.
Backend methods revalidate native liveness while holding their queue lock and return true when the pass made progress. They must never acquire a queue lock while the process-wide custodian registry lock is held.
Return a strong snapshot without retaining the registry lock.
Record cause and warn only on the first consecutive service failure.
A device teardown can prove quiescence after SERVICE releases its queue lock but before this handler runs. Do not resurrect the custodian through the diagnostic table in that race.
A hostile warning handler must not kill the service worker. The queue remains rooted before, during, and after this diagnostic.
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.
This process custodian is runtime infrastructure, like SBCL's finalizer and timer workers: durable ownership lives in the registry, while the worker must not keep a noninteractive Lisp alive after its main thread exits (especially when a failed test deliberately leaves work pending). MAKE-SYSTEM-THREAD is private because callers must serialize it with SBCL's thread-creation mutex; START-THREAD intentionally omits that lock for ephemeral threads under the assumption that it is already held.
Start the singleton service worker. The caller holds the registry lock.
Best-effort worker start which cannot revoke already published custody.
Eventually service rooted queues, exiting atomically when none remain.
CONDITION-WAIT releases the registry lock. No queue lock is ever taken while this process-wide lock is held.
An unexpected worker exit must not strand a newly retained queue.
Root custodian until its ledger and backend submissions are quiescent.
The hash publication is the ownership transfer. Thread creation and wakeup are liveness accelerators and must not leave the public wrapper valid after its teardown was already enqueued.
Drop custodian's root after backend quiescence was proved under its lock.
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.
Durably enqueue native ownership, then logically invalidate resource.
invalidate is called only after ledger owns the complete teardown. Queue
implementations call this while holding the lock which also guards ledger.
Describe every currently retained failed entry in ledger.
Attempt the eligible FIFO prefix in ledger at completed-frontier.
Only a successful eligible prefix leaves the ledger. The first ineligible or failed entry is a FIFO barrier: it and the entire unattempted suffix remain ahead of ownership transferred recursively by teardown callbacks.
A teardown callback can recursively destroy another resource and enter queue maintenance through the same recursive backend lock. The outer batch owns the ordering frontier; leave newly queued work for its next pass rather than letting recursive maintenance overtake it.
Teardown callbacks run under a backend's recursive queue lock and may themselves destroy another resource. Detach this maintenance batch so such transfers enter a fresh queue and cannot be visited or overwritten by the traversal below.
The blocked suffix retains its existing cons cells and original tail, then precedes callback-enqueued ownership.
Preserve the detached suffix even across an unexpected non-local exit from a callback. Backend locks still delimit all mutation.
Eventual service polls independently of callers. Surface the first failed attempt, but do not emit one warning per poll forever; the ledger retains the cause and attempt count for explicit inspection/teardown.
Perform teardown without a live queue, then invalidate resource.
An error leaves the wrapper and its leak finalizer live and is re-signaled as
a structured gpu-native-retirement-error retaining the original cause.
Refuse owner teardown while ledger still owns any native resources.
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.
gpu-resource-leaked conditions recorded for objects the collector had
to reclaim. Inspect or clear this from the REPL to audit leak hygiene.
Record and signal one gpu-resource-leaked warning.
Instances of gpu-provider subclasses are platform-specific
factories for requesting gpu-device instances.
Base class for instantiated GPU resources.
Finished one-shot work accepted by a GPU queue's submit operation.
Abstract receiver for recorded GPU commands.
A retained temporal reconstruction owner and its exact texture contract.
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.
Retry the process-local FIFO of native ownership recovered by finalizers.
Durably route a finalizer's owner through device or the fallback ledger.
The fallback ledger takes ownership before any attempt. Its retryable routing
step records when a backend queue has accepted owner, so a warning promoted to
an error cannot cause a later retry to transfer the same native owner twice.
Return the default queue belonging to device.
Asks the device for a handle to newly created instance
of some object fulfilling the descriptor.
Wrap a platform texture and its retained owner in the HAL.
Record an inspectable GPU command onto encoder.
Issue a queue-scoped GPU command onto queue.
Seal encoder and return one finished, one-shot GPU command buffer.
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.
Block until all work submitted to queue so far has
completed on the GPU.
Copy host data into buffer starting at byte offset.
Wait for buffer's device queue and copy mapped bytes back to the host.
Copy mapped buffer bytes only when its own newest submission is complete.
Return the byte vector and true when ready, or NIL and NIL without waiting.
Unlike read-buffer this does not wait for unrelated newer queue work.
Logically invalidate handle immediately.
Native teardown may be deferred until submitted work which captured handle
has completed.
Copy a proper list or vector value, returning NIL for malformed lists.
Return portable usage syntax as one stable, duplicate-free keyword list.
Preserve the caller's first occurrence: usage order is not semantic, but stable normalization makes descriptors pleasant to inspect.
Return the current portable two-dimensional size contract as (W H 1).
Copy descriptor into the one structural shape every backend receives.
Copy descriptor into the portable two-dimensional texture contract.
Return the CFFI element type and byte size for a one-dimensional data
array of single-floats or unsigned 8-, 16-, 32-, or 64-bit integers.
Return the exact storage size of one texel in portable format.
Return the scalar lane count of a portable vertex attribute format.
The vocabulary is deliberately small and float-only: it names what the mesh and instance products this project actually writes contain, and every backend is expected to accept all of it.
The packed array element type accepted by write-texture for format.
The colour transfer a sampled texture format applies before shader math.
This describes representation decoding, not a quantity. Alpha remains linear for the sRGB formats; the transfer names their RGB-channel behavior.
A render pipeline. Each fragment target may name :BLEND :PREMULTIPLIED-ALPHA; omitted blending retains opaque replacement semantics.
A task/mesh render pipeline.
TASK may be NIL for a direct mesh dispatch. MAX-MESH-WORKGROUPS states the largest task-to-mesh amplification admitted by one task workgroup.
Draw indexed instances from index-buffer.
index-format is :UINT16 or :UINT32. The buffer is carried by the command so
recorded work owns the complete indexed-draw dependency at one boundary.
Issue one WebGPU-style convenience upload onto queue.
Encode one temporal reconstruction from color, depth, and motion.
jitter is the current sample offset in input-pixel units. Motion values are
current-to-previous displacements in normalized input-texture coordinates;
the scaler's input extent binds their conversion to pixels once per frame.
Publish pass's attachment writes to scaler's private synchronization.
Make pass's fragment reads wait for scaler's reconstructed output.
Base condition for errors exposed by the luv GPU API.
Base condition for an operation rejected by a GPU object.
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.
(handle)Logically invalidate HANDLE immediately. Native teardown may be deferred until submitted work which captured HANDLE has completed.
One native teardown durably owned by a GPU queue. READY-AFTER is the queue completion frontier which makes TEARDOWN safe. RESOURCE is retained for diagnosis and, for current backends, also supplies the native handles used by TEARDOWN.
Structured evidence that native GPU ownership could not be retired.
A queue-owned list of native teardowns, including failed attempts.
The lazy process-wide retirement custodian service thread, or NIL.
Newest best-effort worker start error; queue custody remains unaffected.
True once SBCL has begun orderly process shutdown.
Whether retaining a queue custodian starts eventual background service.
(custodian)Perform one safe eventual-retirement service pass for CUSTODIAN. Backend methods revalidate native liveness while holding their queue lock and return true when the pass made progress. They must never acquire a queue lock while the process-wide custodian registry lock is held.
(custodian cause)()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.
Multiplication and scalar scaling.
Logical conjunction of tests and raw truth values.
Logical negation of one test or raw truth value.
The minimum of compatible quantities.
(ledger custodian)(ledger custodian)(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.
(ledger resource ready-after teardown invalidate &optional custodian)Durably enqueue native ownership, then logically invalidate RESOURCE. INVALIDATE is called only after LEDGER owns the complete teardown. Queue implementations call this while holding the lock which also guards LEDGER.
(ledger completed-frontier &key (operation :maintain-queue))Attempt the eligible FIFO prefix in LEDGER at COMPLETED-FRONTIER. Only a successful eligible prefix leaves the ledger. The first ineligible or failed entry is a FIFO barrier: it and the entire unattempted suffix remain ahead of ownership transferred recursively by teardown callbacks.
Logical disjunction of tests and raw truth values.
Test whether two compatible scalars are equal.
Test whether one compatible scalar is greater than another.
(resource teardown invalidate &key (operation :destroy))Perform TEARDOWN without a live queue, then invalidate RESOURCE. An error leaves the wrapper and its leak finalizer live and is re-signaled as a structured GPU-NATIVE-RETIREMENT-ERROR retaining the original cause.
(ledger &key (operation :destroy-device))(&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.
Compare compatible quantities and produce dimensionless values.
GPU-RESOURCE-LEAKED conditions recorded for objects the collector had to reclaim. Inspect or clear this from the REPL to audit leak hygiene.
(resource-class label)Instances of GPU-PROVIDER subclasses are platform-specific factories for requesting GPU-DEVICE instances.
If you're lucky, someone has bound this to a working GPU-PROVIDER.
Base class for instantiated GPU resources.
(&optional (stream *standard-output*))Finished one-shot work accepted by a GPU queue's SUBMIT operation.
(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.
Abstract receiver for recorded GPU commands.
A retained temporal reconstruction owner and its exact texture contract.
(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.
(device owner teardown)Durably route a finalizer's OWNER through DEVICE or the fallback ledger. The fallback ledger takes ownership before any attempt. Its retryable routing step records when a backend queue has accepted OWNER, so a warning promoted to an error cannot cause a later retry to transfer the same native owner twice.
(provider &optional descriptor)(device descriptor)Asks the DEVICE for a handle to newly created instance of some object fulfilling the DESCRIPTOR.
(device native-object owner descriptor)Wrap a platform texture and its retained OWNER in the HAL.
(queue)Block until all work submitted to QUEUE so far has completed on the GPU.
(buffer &key offset size)Wait for BUFFER's device queue and copy mapped bytes back to the host.
(buffer &key offset size)Copy mapped BUFFER bytes only when its own newest submission is complete. Return the byte vector and true when ready, or NIL and NIL without waiting. Unlike READ-BUFFER this does not wait for unrelated newer queue work.
(encoder descriptor)(encoder &optional descriptor)(pass-encoder)(operation descriptor reason details)(value)(usage permitted descriptor reason operation)(size descriptor &optional (operation :create))(descriptor &optional (operation :create))(descriptor &optional (operation :create))(data)Return the CFFI element type and byte size for a one-dimensional DATA array of single-floats or unsigned 8-, 16-, 32-, or 64-bit integers.
(format)Return the scalar lane count of a portable vertex attribute FORMAT. The vocabulary is deliberately small and float-only: it names what the mesh and instance products this project actually writes contain, and every backend is expected to accept all of it.
(queue destination data data-layout size)(format)The colour transfer a sampled texture FORMAT applies before shader math. This describes representation decoding, not a quantity. Alpha remains linear for the sRGB formats; the transfer names their RGB-channel behavior.
How the children of a list are arranged.
(pass-encoder pipeline)(pass-encoder index bind-group)(pass-encoder slot buffer &key (offset 0))(pass-encoder x y width height)(pass-encoder x &optional (y 1) (z 1))(pass-encoder vertex-count
&optional (instance-count 1) (first-vertex 0) (first-instance 0))(pass-encoder index-buffer index-format index-count
&optional (instance-count 1) (first-index 0)
(base-vertex 0) (first-instance 0))Draw indexed instances from INDEX-BUFFER. INDEX-FORMAT is :UINT16 or :UINT32. The buffer is carried by the command so recorded work owns the complete indexed-draw dependency at one boundary.
(pass-encoder x &optional (y 1) (z 1))(encoder texture usage)Prepare TEXTURE for semantic USAGE in ENCODER's following commands. The backend owns any layout transition, hazard barrier, or validation needed to realize the usage. Application code does not dispatch on the backend. #T5MQO0
(encoder scaler color depth motion output jitter reset-p)Encode one temporal reconstruction from COLOR, DEPTH, and MOTION. JITTER is the current sample offset in input-pixel units. Motion values are current-to-previous displacements in normalized input-texture coordinates; the scaler's input extent binds their conversion to pixels once per frame.
(pass scaler)(pass scaler)Luvcraft used to specialize prepare-luvcraft-shadow-map-sampling on Vulkan and Metal encoder classes. That put Vulkan image layout and Metal 4 barrier mechanics in the game even though the game knows only one fact: the completed shadow depth texture will be sampled by the following pass. The game now emits…
Let's define something roughly like a WebGPU style API.
Then we can implement it for our Vulkan bindings.
Later we can implement it for Metal, etc.
This API itself is agnostic of presenting, swapchains, etc.
The base classes omit parent pointer slots. We might, like e.g. McCLIM, also define STANDARD-GPU-QUEUE and so on.