Abstract GPU device: resource creation, queue writes, and submission with shared fail-closed validation. More...
#include "donner/gpu/Device.h"
Classes | |
| struct | MapWaitTestHooks |
| Test seam for donner::gpu::Device::waitForMapping. Production callers pass none; a test injects a clock and a rest so a budget is verified deterministically and without spending it. More... | |
Public Member Functions | |
| virtual | ~Device () |
| Destructor; expires the device-alive token (so handles that outlive the device release nothing) and frees all remaining resources. Backends that submit asynchronously must wait for in-flight submissions in their own destructor before backend state is torn down. | |
| Device (const Device &)=delete | |
| Device & | operator= (const Device &)=delete |
| Device (Device &&)=delete | |
| Device & | operator= (Device &&)=delete |
| uint64_t | deviceId () const |
| Process-unique identity of this device (starts at 1, never reused). Baked into every handle for cross-device validation. | |
| bool | isLost () const |
| True once the backend root this device drives has been declared lost, either by the backend's device-lost callback or by a bounded wait giving up on it. | |
| DeviceLossSnapshot | deviceLossSnapshot () const |
| First-winner loss attribution, once its diagnostic fields have settled. | |
| virtual RcString | deviceLostReason () const |
| Backend-provided loss reason, when the backend retains one. Empty otherwise. | |
| void | markLostAfterWaitTimeout (DeviceLostWaitSite site, std::chrono::milliseconds elapsed, const char *reason) const |
| Declares this device's backend root lost because a bounded wait gave up, recording which wait it was and how long it actually ran. | |
| virtual ShaderSourceKind | shaderSourceKind () const |
| Shader representation accepted by this device. Recording and WebGPU devices use WGSL; native backends override this so callers select the matching build-time artifact. | |
| virtual bool | supportsFullIndexRange (IndexFormat format) const |
Whether indexed draws through this device honor every value of format. Metal and WebGPU always do; a Vulkan device without fullDrawIndexUint32 caps 32-bit indices below the full range, and RenderPassEncoder::setIndexBuffer refuses that format on it rather than let a driver truncate index values. | |
| Result< Buffer > | createBuffer (const BufferDescriptor &descriptor) |
| Creates a buffer. | |
| Result< Texture > | createTexture (const TextureDescriptor &descriptor) |
| Creates a 2D texture. | |
| Result< TextureDescriptor > | textureDescriptor (const Texture &texture) const |
Returns the descriptor texture was created with, by value. | |
| Result< TextureView > | createTextureView (const Texture &texture, const TextureViewDescriptor &descriptor) |
Creates a view of texture covering the whole texture. | |
| Result< Sampler > | createSampler (const SamplerDescriptor &descriptor) |
| Creates a sampler. | |
| Result< BindGroupLayout > | createBindGroupLayout (const BindGroupLayoutDescriptor &descriptor) |
| Creates a bind group layout. | |
| Result< BindGroup > | createBindGroup (const BindGroupDescriptor &descriptor) |
| Creates a bind group. | |
| Result< PipelineLayout > | createPipelineLayout (const PipelineLayoutDescriptor &descriptor) |
| Creates a pipeline layout. | |
| Result< ShaderModule > | createShaderModule (const ShaderModuleDescriptor &descriptor) |
| Creates a shader module from trusted generated source. | |
| Result< RenderPipeline > | createRenderPipeline (const RenderPipelineDescriptor &descriptor) |
| Creates a render pipeline. | |
| Result< ComputePipeline > | createComputePipeline (const ComputePipelineDescriptor &descriptor) |
| Creates a compute pipeline. | |
| Status | destroyBuffer (Buffer &&buffer) |
| Destroys a buffer (see the destroy contract above). | |
| Status | destroyTexture (Texture &&texture) |
| Destroys a texture (see the destroy contract above). | |
| Status | destroyTextureView (TextureView &&textureView) |
| Destroys a texture view (see the destroy contract above). | |
| Status | destroySampler (Sampler &&sampler) |
| Destroys a sampler (see the destroy contract above). | |
| Status | destroyBindGroupLayout (BindGroupLayout &&bindGroupLayout) |
| Destroys a bind group layout (see the destroy contract above). | |
| Status | destroyBindGroup (BindGroup &&bindGroup) |
| Destroys a bind group (see the destroy contract above). | |
| Status | destroyPipelineLayout (PipelineLayout &&pipelineLayout) |
| Destroys a pipeline layout (see the destroy contract above). | |
| Status | destroyShaderModule (ShaderModule &&shaderModule) |
| Destroys a shader module (see the destroy contract above). | |
| Status | destroyRenderPipeline (RenderPipeline &&renderPipeline) |
| Destroys a render pipeline (see the destroy contract above). | |
| Status | destroyComputePipeline (ComputePipeline &&computePipeline) |
| Destroys a compute pipeline (see the destroy contract above). | |
| Status | destroyBufferBacking (Buffer &&buffer) |
Destroys buffer and releases its backend allocation at once, rather than leaving the allocation to the backend's own collector. | |
| Status | destroyTextureBacking (Texture &&texture) |
Destroys texture and releases its backend allocation at once, the texture counterpart of destroyBufferBacking; a succession of resized render targets is where the deferred release shows up as retained memory. | |
| bool | ownsTextureBacking (const Texture &texture) const |
Whether texture names backing this device allocated, rather than memory some other owner holds and this device only named. | |
| Result< TextureExport > | exportTexture (const Texture &texture) |
Exports texture so another runtime device over the same backend device can register it. | |
| Result< Texture > | registerTexture (const TextureExport &source) |
| Registers a texture another runtime device exported, as a read-only texture of this one. | |
| bool | waitForTextureSource (const Texture ®istration, double timeoutSeconds) |
Waits until work naming registration may be submitted, the budget runs out, or either device is lost, and reports whether it may. | |
| SerialWaitResult | waitForTextureSourceUnlessStalled (const Texture ®istration, std::chrono::milliseconds stallBound) |
waitForTextureSource for a caller whose bound exists to detect a hung producer: the wait gives up only once the producer has made no progress for stallBound, measured from that progress, rather than giving the producer's whole backlog a fixed budget. | |
| uint64_t | sharedTextureTailBytes () const |
| Bytes of this device's exported textures that are still held by an export token or a registration after this device released its own handle. | |
| Result< std::unique_ptr< CommandEncoder > > | createCommandEncoder () |
| Creates a command encoder recording against this device. The encoder must not outlive the device. | |
| Result< Surface > | createSurface (const SurfaceDescriptor &descriptor) |
| Creates a surface presenting to a platform object. | |
| Result< SurfaceCapabilities > | surfaceCapabilities (const Surface &surface) const |
What surface supports, for choosing a configuration. | |
| Status | configureSurface (const Surface &surface, const SurfaceConfiguration &configuration) |
Configures how surface presents, replacing any previous configuration. | |
| Result< SurfaceTexture > | acquireCurrentTexture (const Surface &surface) |
Acquires the texture for the next frame of surface. | |
| Result< SurfaceStatus > | presentSurface (const Surface &surface) |
Presents the texture acquired from surface and invalidates it. | |
| Status | abandonCurrentTexture (const Surface &surface) |
Releases the acquired texture of surface without presenting it, for a frame the caller decided not to show. | |
| Status | destroySurface (Surface &&surface) |
| Destroys a surface (see the destroy contract above). | |
| Result< BufferMapping > | mapBufferAsync (const Buffer &buffer, MapMode mode, uint64_t offsetBytes, uint64_t byteCount) |
Begins mapping a range of buffer for host access, and returns the handle that names the mapping. | |
| Result< MapSliceReport > | pollMapping (const BufferMapping &mapping) |
| Polls a mapping once without blocking or yielding; ready mappings become readable. | |
| Result< MapWaitReport > | waitForMapping (const BufferMapping &mapping, const MapWaitParams ¶ms, const std::function< bool()> &shouldCancel, const MapWaitTestHooks &testHooks={}) |
| Waits for a pending mapping in slices, until it completes, the caller stops it, the budget runs out, or the device is lost. | |
| Result< std::span< const uint8_t > > | mappedBytes (const BufferMapping &mapping) const |
| Returns the mapped bytes of a completed mapping. | |
| Status | unmapBuffer (BufferMapping &&mapping) |
| Releases a mapping, invalidating the handle and every copy of it. | |
| Status | writeBuffer (const Buffer &buffer, uint64_t offsetBytes, std::span< const uint8_t > data) |
Writes data into buffer at offsetBytes. | |
| Status | writeTexture (const Texture &texture, std::span< const uint8_t > data, const TexelCopyBufferLayout &dataLayout, const Extent2d &writeSize, const Origin2d &destinationOrigin={}) |
Writes texel rows from data into the writeSize rectangle of texture whose top-left texel is destinationOrigin, leaving every texel outside that rectangle unchanged. | |
| Result< uint64_t > | submit (CommandBuffer commandBuffer) |
| Submits a finished command buffer, consuming it, and returns the assigned submission serial. | |
| Result< uint64_t > | submit (std::span< CommandBuffer > commandBuffers) |
| Submits finished command buffers as one submission, consuming them, and returns the single assigned submission serial. | |
| void | poll () |
| Processes deferred destructions: releases the backend object of every destroyed resource whose last referencing submission has completed (completedSerial), and recycles its slot. | |
| void | pollCompletionOnce () |
| Drive one nonblocking backend completion iteration even when no resource destroy is pending. | |
| bool | hasPendingDestroys () const |
| Whether a completed submission can still release a backend object. Owner-thread only. | |
| uint64_t | lastSubmittedSerial () const |
| Serial assigned to the most recent submission (0 if none yet). | |
| virtual uint64_t | completedSerial () const =0 |
| Serial of the most recent submission the backend has finished executing (0 if none). The recording backend completes instantly, so this equals lastSubmittedSerial there. | |
| bool | waitForSerial (uint64_t serial, double timeoutSeconds) |
Blocks until completedSerial reaches serial, timeoutSeconds elapses, or the backend gives up on the work, and reports whether the submission completed. | |
| SerialWaitResult | waitForSerialUnlessStalled (uint64_t serial, std::chrono::milliseconds stallBound) |
Blocks until completedSerial reaches serial, giving up only when the work the serial waits behind stops making progress. | |
| std::optional< std::chrono::steady_clock::time_point > | lastProgress () |
| When the work this device's submissions wait behind last made progress, or nothing when the backend has no notion of progress. | |
| Status | installObserver (DeviceObserver &observer) |
Installs observer to be notified of the work this device accepts (see DeviceObserver). | |
| void | removeObserver (const DeviceObserver &observer) |
Removes observer when it is the installed one and otherwise changes nothing, so an owner can only ever remove its own. | |
| const DeviceObserver * | observer () const |
| The installed observer, or null when there is none. | |
Static Public Attributes | |
| static constexpr size_t | kMaxCommandBuffersPerSubmission = 256 |
| Most command buffers one submission may carry. | |
| static constexpr double | kMaxWaitSeconds = 1.0e6 |
| Longest a single waitForSerial may block, in seconds. A budget above this is clamped to it; the value is far past any deadline a caller has, and keeps the conversion to the clock's own duration from overflowing on a caller that means "wait indefinitely" and says so with a very large number. | |
Protected Member Functions | |
| Device () | |
| Constructor for backends; assigns the process-unique device identity. | |
| virtual void | onPollBackend () |
| One nonblocking backend event iteration before a pending-destroy scan. Native devices report completion directly; callback-driven adapters override this hook. | |
| void | adoptLostState (std::shared_ptr< DeviceLostState > state) |
| Adopts the sticky loss condition of a backend root this device shares with another device. | |
| uint64_t | bufferLastUseSerial (uint32_t slotIndex) const |
| Last accepted submission referencing a buffer slot already validated by the caller. | |
| uint64_t | textureLastUseSerial (uint32_t slotIndex) const |
| Last accepted submission referencing a texture slot already validated by the caller. | |
| virtual Status | onCreateBuffer (uint32_t slotIndex, const BufferDescriptor &descriptor)=0 |
Backend hook: a buffer passed validation and occupies slotIndex. | |
| virtual Status | onCreateTexture (uint32_t slotIndex, const TextureDescriptor &descriptor)=0 |
Backend hook: a texture passed validation and occupies slotIndex. | |
| virtual Status | onCreateTextureView (uint32_t slotIndex, uint32_t textureSlotIndex, const TextureViewDescriptor &descriptor)=0 |
Backend hook: a texture view passed validation and occupies slotIndex. | |
| virtual Status | onCreateSampler (uint32_t slotIndex, const SamplerDescriptor &descriptor)=0 |
Backend hook: a sampler passed validation and occupies slotIndex. | |
| virtual Status | onCreateBindGroupLayout (uint32_t slotIndex, const BindGroupLayoutDescriptor &descriptor)=0 |
Backend hook: a bind group layout passed validation and occupies slotIndex. | |
| virtual Status | onCreateBindGroup (uint32_t slotIndex, const BindGroupDescriptor &descriptor)=0 |
Backend hook: a bind group passed validation and occupies slotIndex. | |
| virtual Status | onCreatePipelineLayout (uint32_t slotIndex, const PipelineLayoutDescriptor &descriptor)=0 |
Backend hook: a pipeline layout passed validation and occupies slotIndex. | |
| virtual Status | onCreateShaderModule (uint32_t slotIndex, const ShaderModuleDescriptor &descriptor)=0 |
Backend hook: a shader module passed validation and occupies slotIndex. | |
| virtual Status | onCreateRenderPipeline (uint32_t slotIndex, const RenderPipelineDescriptor &descriptor)=0 |
Backend hook: a render pipeline passed validation and occupies slotIndex. | |
| virtual Status | onCreateComputePipeline (uint32_t slotIndex, const ComputePipelineDescriptor &descriptor)=0 |
Backend hook: a compute pipeline passed validation and occupies slotIndex. | |
| virtual void | onRetireBuffer (uint32_t slotIndex) |
| Backend hook: a buffer handle was retired. Discard unsubmitted work, but keep native resources alive until onDestroyResource. | |
| virtual void | onRetireTexture (uint32_t slotIndex) |
| Backend hook: a texture handle was retired. Discard unsubmitted work, but keep native resources alive until onDestroyResource. | |
| virtual void | onDestroyResource (std::string_view resourceName, uint32_t slotIndex)=0 |
| Backend hook: a retired resource is no longer used by submitted work and can be released. | |
| virtual void | onDestroyBufferBacking (uint32_t slotIndex) |
Backend hook: destroyBufferBacking validated slotIndex and is about to destroy its handle; release the allocation now rather than when the slot is recycled. | |
| virtual void | onDestroyTextureBacking (uint32_t slotIndex) |
| Backend hook: the texture counterpart of onDestroyBufferBacking, with the same default. A slot whose backing this device does not own keeps its allocation. | |
| virtual bool | onOwnsTextureBacking (uint32_t slotIndex) const |
Backend hook: whether slotIndex holds backing this device allocated. | |
| virtual BackendDeviceIdentity | backendDeviceIdentity () const |
| Backend hook: which backend family this device belongs to and which native device it records against, for matching an export against a registering device. | |
| virtual Result< BackendTextureExport > | onExportTexture (uint32_t slotIndex) |
Backend hook: export the texture in slotIndex, which the runtime has already validated as a live texture this device allocated and no surface has out. | |
| virtual Status | onRegisterTexture (uint32_t slotIndex, const ExportedTextureBacking &backing) |
Backend hook: name another device's exported texture in slotIndex. | |
| virtual bool | onTextureWritePending (uint32_t slotIndex) const |
Backend hook: whether the write writeTexture just accepted for slotIndex is waiting for this device's next submission, rather than complete or ordered on the queue already. | |
| virtual bool | onWaitForSerial (uint64_t serial, double timeoutSeconds) |
| Backend hook: waitForSerial with a budget already clamped to zero or more. | |
| virtual SerialWaitResult | onWaitForSerialUnlessStalled (uint64_t serial, std::chrono::milliseconds stallBound) |
| Backend hook: waitForSerialUnlessStalled with a bound already clamped. | |
| virtual std::optional< std::chrono::steady_clock::time_point > | onLastProgress () |
| Backend hook: lastProgress. The default reports no notion of progress. | |
| virtual Status | onWriteBuffer (uint32_t slotIndex, uint64_t offsetBytes, std::span< const uint8_t > data)=0 |
| Backend hook: a validated buffer write. | |
| virtual Status | onWriteTexture (uint32_t slotIndex, std::span< const uint8_t > data, const TexelCopyBufferLayout &dataLayout, const Extent2d &writeSize, const Origin2d &destinationOrigin)=0 |
Backend hook: a validated texture write. The written rectangle is writeSize texels wide and tall with its top-left texel at destinationOrigin; texels outside it keep their contents. | |
| Status | validateBufferHandleForBackend (const Buffer &buffer) const |
| Validates a buffer handle for backend-provided auxiliary entry points (test readback helpers and similar), running the same null/device-identity/generation checks the template-method public API performs before its hooks. | |
| Status | validateTextureHandleForBackend (const Texture &texture) const |
| Validates a texture handle for backend-provided auxiliary entry points, running the same null/device-identity/generation checks the template-method public API performs. | |
| Status | validateTextureViewHandleForBackend (const TextureView &textureView) const |
| Validates a texture view handle for backend-provided auxiliary entry points: the view itself plus a re-resolution of its viewed texture, so a view of a destroyed (or slot-recycled) texture fails closed exactly like it does on the normal Device paths. | |
| Status | validateBufferMappingHandleForBackend (const BufferMapping &mapping) const |
| Validates a buffer-mapping handle for backend-provided auxiliary entry points, running the same null/device-identity/generation checks the template-method public API performs, so a stale handle cannot read state belonging to the slot's new occupant. | |
| virtual Status | onMapBufferAsync (uint32_t mappingSlotIndex, uint32_t bufferSlotIndex, MapMode mode, uint64_t offsetBytes, uint64_t byteCount) |
| Backend hook: begin mapping a buffer range. | |
| virtual MapSliceReport | onWaitMappingSlice (uint32_t mappingSlotIndex, double sliceSeconds) |
Backend hook: wait up to sliceSeconds for a pending mapping, and report what it found and how it spent the slice. | |
| virtual Result< std::span< const uint8_t > > | onMappedBytes (uint32_t mappingSlotIndex) const |
| Backend hook: bytes of a completed mapping. | |
| virtual void | onUnmapBuffer (uint32_t mappingSlotIndex) |
| Backend hook: release a mapping. | |
| virtual Status | onCreateSurface (uint32_t slotIndex, const SurfaceDescriptor &descriptor) |
| Backend hook: create a surface for a platform object. | |
| virtual Result< SurfaceCapabilities > | onSurfaceCapabilities (uint32_t slotIndex) const |
| Backend hook: what a surface supports. | |
| virtual Status | onConfigureSurface (uint32_t slotIndex, const SurfaceConfiguration &configuration) |
| Backend hook: apply a configuration. | |
| virtual Result< SurfaceStatus > | onAcquireCurrentTexture (uint32_t slotIndex, uint32_t textureSlotIndex) |
| Backend hook: acquire the next frame's texture and report the surface's state. | |
| virtual Result< SurfaceStatus > | onPresentSurface (uint32_t slotIndex) |
| Backend hook: present the acquired texture. | |
| virtual void | onAbandonCurrentTexture (uint32_t slotIndex) |
| Backend hook: drop the acquired texture without presenting. | |
| uint64_t | lastTextureUseSerial (uint32_t textureSlotIndex) const |
Serial of the last submission that referenced the texture at textureSlotIndex, or 0 when nothing has submitted work naming it. | |
| virtual void | onDestroySurface (uint32_t slotIndex) |
| Backend hook: release the platform state of a surface that is going away. | |
| virtual Status | onSubmit (uint64_t submissionSerial, std::span< const SubmittedCommandBuffer > commandBuffers)=0 |
| Backend hook: validated command buffers were submitted as one submission. | |
| virtual Status | onSubmitAfterSources (uint64_t submissionSerial, std::span< const SubmittedCommandBuffer > commandBuffers, std::span< const SourceWait > waits) |
| Backend hook: onSubmit for a submission that must also wait on the device, before any of its work runs, for producer work it names through registrations ordered on the device (SourceOrdering::WaitOnDevice). | |
| virtual uint64_t | onTextureWriteByteCount (std::span< const uint8_t > data) const |
| Backend hook: the bytes the write onWriteTexture just accepted handed the backend's queue, which DeviceObserver::onTextureWritten reports. | |
| void | notifyObserverOfBackendSubmission () const |
| Reports a queue submission the backend made on its own, outside submit, to the installed observer as a submission of no command buffers and no draws. | |
Friends | |
| class | CommandEncoder |
Abstract GPU device: resource creation, queue writes, and submission with shared fail-closed validation.
The public API is non-virtual and validates every descriptor, handle, and byte range before delegating to protected on* virtuals (template-method pattern), so every backend - the deterministic RecordingDevice and the platform backends - inherits identical fail-closed behavior. Validation runs in release builds too: invalid input returns a GpuError, never asserts.
Enforced limits are documented in GpuLimits.h. Handle validation checks device identity (GpuErrorType::DeviceMismatch) and slot generation (GpuErrorType::InvalidHandle), so destroyed or foreign handles fail before reaching a backend.
Lifetime: handles are move-only RAII - dropping a live handle releases the resource, an explicit destroy*(std::move(handle)) call releases it early and reports errors, and device teardown frees everything that remains. A handle that outlives its device releases nothing (its device-alive token has expired). Destruction is deferred by submission serial: destroying a resource makes its handles and references stale immediately, but the backend object is kept alive - and its slot is not reused - until every submission referencing it has completed (completedSerial). Deferred backend releases are processed by poll and opportunistically by destroy* and submit.
Two resource kinds are intentionally exempt from submission pinning because commands never reference them: PipelineLayout and ShaderModule are consumed at pipeline creation only, so destroying one releases its backend object immediately. Backends must snapshot or retain whatever they need from them when the pipeline is created (Metal's compiled pipeline state retains its functions, and each Vulkan pipeline retains its native pipeline layout).
Thread affinity: a Device and everything created from it must be used from one thread at a time, matching the async-renderer worker ownership model.
| struct donner::gpu::Device::MapWaitTestHooks |
Test seam for donner::gpu::Device::waitForMapping. Production callers pass none; a test injects a clock and a rest so a budget is verified deterministically and without spending it.
Releases the acquired texture of surface without presenting it, for a frame the caller decided not to show.
| surface | Live surface with an acquired texture. |
| Result< SurfaceTexture > donner::gpu::Device::acquireCurrentTexture | ( | const Surface & | surface | ) |
Acquires the texture for the next frame of surface.
The texture is valid until the matching presentSurface, abandonCurrentTexture, or a reconfiguration - each of those invalidates it, so drawing into a presented texture is a reported validation failure rather than a write to a texture the platform now owns.
A non-success status can still come with a usable texture: a surface that has drifted out of date usually still presents, so the caller decides between drawing this frame and reconfiguring first.
| surface | Live, configured surface. |
|
protected |
Adopts the sticky loss condition of a backend root this device shares with another device.
Called by a backend at construction, before anything can observe the device. A root drives several runtime devices - a UI context, a worker context, an isolated readback context - and they must agree on whether it has stopped answering, so the second and later devices over one root take the condition the first one published into rather than minting their own.
| state | Condition to share; ignored when null, so a backend may pass an absent one. |
|
nodiscardprotectedvirtual |
Backend hook: which backend family this device belongs to and which native device it records against, for matching an export against a registering device.
The default names nothing, which is the answer for a backend whose runtime devices never share a native device.
Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protected |
Last accepted submission referencing a buffer slot already validated by the caller.
| slotIndex | A validated live buffer slot. |
|
pure virtual |
Serial of the most recent submission the backend has finished executing (0 if none). The recording backend completes instantly, so this equals lastSubmittedSerial there.
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
| Status donner::gpu::Device::configureSurface | ( | const Surface & | surface, |
| const SurfaceConfiguration & | configuration ) |
Configures how surface presents, replacing any previous configuration.
This is how a surface follows its window: a resize reconfigures with the new extent rather than creating a new surface, and it is the recovery from SurfaceStatus::Outdated. Reconfiguring abandons any texture currently acquired from the surface.
| surface | Live surface. |
| configuration | Format, usage, extent, pacing and alpha compositing. |
| Result< BindGroup > donner::gpu::Device::createBindGroup | ( | const BindGroupDescriptor & | descriptor | ) |
Creates a bind group.
Fails closed unless every layout binding is matched by exactly one entry whose resource is live, belongs to this device, matches the layout's BindingType, and carries the usage that binding type requires.
| descriptor | Validated bind group descriptor. |
| Result< BindGroupLayout > donner::gpu::Device::createBindGroupLayout | ( | const BindGroupLayoutDescriptor & | descriptor | ) |
Creates a bind group layout.
Fails closed on duplicate binding indices, out-of-limit binding counts or indices, or empty per-entry visibility.
| descriptor | Validated layout descriptor. |
| Result< Buffer > donner::gpu::Device::createBuffer | ( | const BufferDescriptor & | descriptor | ) |
Creates a buffer.
Fails closed on zero or oversized byteSize or empty usage.
| descriptor | Validated buffer descriptor. |
| Result< ComputePipeline > donner::gpu::Device::createComputePipeline | ( | const ComputePipelineDescriptor & | descriptor | ) |
Creates a compute pipeline.
Fails closed on invalid layout/module references, an empty entry point, or a workgroup size that is zero in any dimension, exceeds a per-axis cap, or declares more than kMaxComputeInvocationsPerWorkgroup invocations.
| descriptor | Validated pipeline descriptor. |
| Result< PipelineLayout > donner::gpu::Device::createPipelineLayout | ( | const PipelineLayoutDescriptor & | descriptor | ) |
Creates a pipeline layout.
Fails closed on out-of-limit group counts or invalid layout references.
| descriptor | Validated pipeline layout descriptor. |
| Result< RenderPipeline > donner::gpu::Device::createRenderPipeline | ( | const RenderPipelineDescriptor & | descriptor | ) |
Creates a render pipeline.
Fails closed on invalid layout/module references, empty entry points, vertex attributes that overflow their stride, duplicate shader locations, empty or out-of-limit target lists, or multisampleCount != 1.
| descriptor | Validated pipeline descriptor. |
| Result< Sampler > donner::gpu::Device::createSampler | ( | const SamplerDescriptor & | descriptor | ) |
Creates a sampler.
| descriptor | Validated sampler descriptor. |
| Result< ShaderModule > donner::gpu::Device::createShaderModule | ( | const ShaderModuleDescriptor & | descriptor | ) |
Creates a shader module from trusted generated source.
Fails closed on empty source text. Native Metal also requires engaged buffer-binding metadata before compiling any MSL module; an explicitly empty list declares that the module uses no buffers.
| descriptor | Validated shader module descriptor. |
| Result< Surface > donner::gpu::Device::createSurface | ( | const SurfaceDescriptor & | descriptor | ) |
Creates a surface presenting to a platform object.
The surface is not usable until configureSurface succeeds: a surface knows what it presents to, and a configuration knows how.
| descriptor | Label and platform object to present to. |
| Result< Texture > donner::gpu::Device::createTexture | ( | const TextureDescriptor & | descriptor | ) |
Creates a 2D texture.
Fails closed on zero or oversized extents, empty usage, or sampleCount != 1.
| descriptor | Validated texture descriptor. |
| Result< TextureView > donner::gpu::Device::createTextureView | ( | const Texture & | texture, |
| const TextureViewDescriptor & | descriptor ) |
Creates a view of texture covering the whole texture.
| texture | Texture to view; must be a live handle of this device. |
| descriptor | Validated view descriptor. |
Destroys a bind group (see the destroy contract above).
| bindGroup | Handle to destroy. |
| Status donner::gpu::Device::destroyBindGroupLayout | ( | BindGroupLayout && | bindGroupLayout | ) |
Destroys a bind group layout (see the destroy contract above).
| bindGroupLayout | Handle to destroy. |
Destroys a buffer (see the destroy contract above).
| buffer | Handle to destroy. |
Destroys buffer and releases its backend allocation at once, rather than leaving the allocation to the backend's own collector.
destroyBuffer ends the handle; on a backend that reference-counts its allocations, the memory behind it stays resident until whatever else still names it lets go. A readback buffer whose map was cancelled, and a pooled readback set evicted to keep a pool inside its ceiling, both have to give their memory back at that moment instead of whenever a collector next runs, so this operation says so explicitly.
The handle is validated before anything is freed, so a stale, foreign, or already-destroyed handle is reported and reaches nothing - in particular not whatever now occupies its slot. The destroy contract above still applies in full: the handle is consumed either way, and one naming a live resource of another device is released on that device.
| buffer | Live buffer handle of this device; consumed either way. |
| Status donner::gpu::Device::destroyComputePipeline | ( | ComputePipeline && | computePipeline | ) |
Destroys a compute pipeline (see the destroy contract above).
| computePipeline | Handle to destroy. |
| Status donner::gpu::Device::destroyPipelineLayout | ( | PipelineLayout && | pipelineLayout | ) |
Destroys a pipeline layout (see the destroy contract above).
| pipelineLayout | Handle to destroy. |
| Status donner::gpu::Device::destroyRenderPipeline | ( | RenderPipeline && | renderPipeline | ) |
Destroys a render pipeline (see the destroy contract above).
| renderPipeline | Handle to destroy. |
Destroys a sampler (see the destroy contract above).
| sampler | Handle to destroy. |
| Status donner::gpu::Device::destroyShaderModule | ( | ShaderModule && | shaderModule | ) |
Destroys a shader module (see the destroy contract above).
| shaderModule | Handle to destroy. |
Destroys a surface (see the destroy contract above).
| surface | Handle to destroy. |
Destroys a texture (see the destroy contract above).
| texture | Handle to destroy. |
Destroys texture and releases its backend allocation at once, the texture counterpart of destroyBufferBacking; a succession of resized render targets is where the deferred release shows up as retained memory.
The same caller precondition applies.
A texture whose backing this device does not own (see ownsTextureBacking) keeps its allocation: the owner is whoever registered it or handed the frame out, and destroying the handle only forgets this device's name for it. That is enforced here rather than left to each backend, so the guarantee holds for every one of them.
| texture | Live texture handle of this device; consumed either way. |
| Status donner::gpu::Device::destroyTextureView | ( | TextureView && | textureView | ) |
Destroys a texture view (see the destroy contract above).
| textureView | Handle to destroy. |
|
inlinevirtual |
Backend-provided loss reason, when the backend retains one. Empty otherwise.
Reimplemented in donner::gpu::browser::BrowserDevice.
| Result< TextureExport > donner::gpu::Device::exportTexture | ( | const Texture & | texture | ) |
Exports texture so another runtime device over the same backend device can register it.
Runs on this device's thread, like every other operation that reads its table: the handle is resolved here, so a null or stale handle fails with GpuErrorType::InvalidHandle and one of another device with GpuErrorType::DeviceMismatch. Nothing is allocated from the backend, nothing is submitted, and nothing waits.
The token holds the texture's allocation: it stays alive while the token, or any registration made from it, is alive, including after this device releases its handle.
A frame a surface currently has out goes back to that surface when it is presented. It is exported only by a backend whose registrations submit to this device's own queue (SourceOrdering::SharedQueue): a reader's work recorded before the present then runs before it. The caller must not record reads of such a registration after the frame is presented. A backend whose readers have their own queues refuses the frame with GpuErrorType::InvalidState, because their reads could land after the surface took it back.
Also refused with GpuErrorType::InvalidState for a registration of another device's texture, which is exported from the device that allocated it; with GpuErrorType::DeviceLost once this device is lost; and with GpuErrorType::Unsupported by a backend whose runtime devices never share a native device.
| texture | Live texture of this device. |
|
nodiscard |
Installs observer to be notified of the work this device accepts (see DeviceObserver).
A device carries at most one observer. Installing the one already installed is accepted; installing a different one while another is installed is refused with GpuErrorType::InvalidState and changes nothing, because replacing it would leave its owner counting nothing while every bound checked against those counts passed.
Non-owning: the caller keeps observer alive until it removes it with removeObserver. With none installed, each operation costs one null check.
| observer | Observer to notify. |
|
inline |
True once the backend root this device drives has been declared lost, either by the backend's device-lost callback or by a bounded wait giving up on it.
Sticky: never resets. The condition belongs to the root rather than to this device, so every device sharing the root reports it - a root that stopped answering has stopped answering all of them. Once lost, rendering output is undefined, readbacks return promptly, and teardown skips GPU waits, except that Vulkan teardown still waits, bounded by queue progress, to prove its submissions complete before it frees native objects.
| std::optional< std::chrono::steady_clock::time_point > donner::gpu::Device::lastProgress | ( | ) |
When the work this device's submissions wait behind last made progress, or nothing when the backend has no notion of progress.
Progress is a command buffer finishing on the queue this device's work runs on, work being committed to that queue while none of it was outstanding, which starts the clock, and, while a submission waits on the GPU for another device's work, that device's progress until the awaited work completes. It can predate any particular wait: a queue that stopped making progress before a caller started waiting has been stalled since then. Owner-thread only.
|
protected |
Serial of the last submission that referenced the texture at textureSlotIndex, or 0 when nothing has submitted work naming it.
For a backend that has to order something against one texture's own work rather than against whatever the device submitted most recently, which is not the same thing as soon as a caller submits anything else between the two.
| textureSlotIndex | Slot of the texture. |
| Result< BufferMapping > donner::gpu::Device::mapBufferAsync | ( | const Buffer & | buffer, |
| MapMode | mode, | ||
| uint64_t | offsetBytes, | ||
| uint64_t | byteCount ) |
Begins mapping a range of buffer for host access, and returns the handle that names the mapping.
The mapping is not readable yet: pollMapping or waitForMapping decides when it is. The returned handle is what keeps the mapped range reachable - unmapBuffer consumes it and every copy of it goes stale at that moment, so a read through a handle whose mapping has been released is a reported validation failure rather than a read of memory that is no longer there.
A buffer carries at most one mapping at a time: a second request while one is open is refused with GpuErrorType::InvalidState. Two mappings of one buffer would each be released by the other's unmapBuffer, so one handle would decide when another handle's bytes went away.
Holding a mapping is not ownership of the buffer. Destroying the buffer is allowed while a mapping is open, and invalidates it: the handle stays resolvable and reads through it are refused, rather than the buffer being kept alive by a reader that has not finished.
| buffer | Buffer to map; needs BufferUsage::MapRead. |
| mode | How the host will access the range. |
| offsetBytes | Byte offset of the mapped range. |
| byteCount | Length of the mapped range; must be nonzero and fit the buffer. |
| Result< std::span< const uint8_t > > donner::gpu::Device::mappedBytes | ( | const BufferMapping & | mapping | ) | const |
Returns the mapped bytes of a completed mapping.
Fails closed when the mapping is stale, belongs to another device, has not completed, named a buffer that has since been destroyed, or belongs to a device that has been lost (GpuErrorType::DeviceLost): the span is only valid while the handle names a live, ready mapping. Completion means a donner::gpu::Device::waitForMapping reported MapWaitOutcome::Ready, or pollMapping reported MapSliceState::Ready; until one has, reading is refused rather than racing whatever the GPU is still writing.
The span aliases the backend's allocation rather than a copy of it, so it lives only as long as the mapping does: unmapBuffer, destroying the buffer, or losing the device all end it. A caller that keeps the bytes past any of those copies them out first. The UTILS_LIFETIME_BOUND annotation states that contract to the compiler; it is not relied on to catch every misuse, because the span is returned inside a Result and the dangling diagnostic does not see through an unannotated class template.
| mapping | Live, completed mapping of this device. |
| void donner::gpu::Device::markLostAfterWaitTimeout | ( | DeviceLostWaitSite | site, |
| std::chrono::milliseconds | elapsed, | ||
| const char * | reason ) const |
Declares this device's backend root lost because a bounded wait gave up, recording which wait it was and how long it actually ran.
The attribution is what turns "rendering stopped" into a diagnosable report, and it is only available at the wait site. Loss stays sticky, and only the call that declares it records an attribution; see DeclareDeviceLostAfterWaitTimeout for why that rule is what keeps a backend-reported loss from being relabelled as a wait timeout. Const because observers treat the condition as shared diagnostic state and the waits that discover a hang run through const accessors.
| site | Which bounded wait gave up. |
| elapsed | Wall time that wait spent before giving up. |
| reason | Human-readable cause, logged once. |
|
protectedvirtual |
Backend hook: drop the acquired texture without presenting.
| slotIndex | Slot of the surface. |
Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: acquire the next frame's texture and report the surface's state.
| slotIndex | Slot of the surface. |
| textureSlotIndex | Slot the runtime allocated for the acquired texture. |
Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: apply a configuration.
| slotIndex | Slot of the surface. |
| configuration | Configuration to apply. |
Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a bind group passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a bind group layout passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a buffer passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a compute pipeline passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a pipeline layout passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a render pipeline passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a sampler passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a shader module passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: create a surface for a platform object.
Defaults to reporting presentation as unsupported, so a backend that cannot present needs no implementation.
| slotIndex | Slot the surface occupies. |
| descriptor | Label and platform object. |
Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a texture passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| descriptor | Validated descriptor. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a texture view passed validation and occupies slotIndex.
| slotIndex | Slot index of the new resource. |
| textureSlotIndex | Slot index of the viewed texture. |
| descriptor | Validated descriptor. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: destroyBufferBacking validated slotIndex and is about to destroy its handle; release the allocation now rather than when the slot is recycled.
The default does nothing, which is the whole answer for a backend that already frees the allocation as soon as the last submission naming it completes - there is nothing left to give back earlier, and a backend must never free memory a submitted command still reads.
| slotIndex | Validated live buffer slot. |
Reimplemented in donner::geode::GeodeWgpuAdapterDevice.
|
protectedpure virtual |
Backend hook: a retired resource is no longer used by submitted work and can be released.
| resourceName | Resource type name, e.g. "buffer". |
| slotIndex | Slot index of the destroyed resource. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: release the platform state of a surface that is going away.
Runs once per surface, when it is destroyed or when its last handle is dropped, after any frame it still held has been handed back through onAbandonCurrentTexture. The slot is reused by the next surface, so a backend that keeps per-surface state clears it here rather than leaving the next surface to find its predecessor's.
| slotIndex | Slot of the surface. |
Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: the texture counterpart of onDestroyBufferBacking, with the same default. A slot whose backing this device does not own keeps its allocation.
| slotIndex | Validated live texture slot. |
Reimplemented in donner::geode::GeodeWgpuAdapterDevice.
|
protectedvirtual |
Backend hook: export the texture in slotIndex, which the runtime has already validated as a live texture this device allocated and no surface has out.
The default refuses with GpuErrorType::Unsupported: a backend that reaches each native device through exactly one runtime device has no other device that could name the texture.
| slotIndex | Validated live texture slot. |
Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: lastProgress. The default reports no notion of progress.
Reimplemented in donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: begin mapping a buffer range.
Defaults to reporting the capability as unsupported, so a backend without host mapping needs no implementation and callers get a clean unsupported result rather than a missing symbol.
| mappingSlotIndex | Slot the mapping occupies. |
| bufferSlotIndex | Slot of the buffer being mapped. |
| mode | How the host will access the range. |
| offsetBytes | Byte offset of the mapped range. |
| byteCount | Length of the mapped range. |
Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: bytes of a completed mapping.
| mappingSlotIndex | Slot of the mapping. |
Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
nodiscardprotectedvirtual |
Backend hook: whether slotIndex holds backing this device allocated.
Asked for a validated slot that is not a surface's acquired frame, from two places: the public ownsTextureBacking, and createTexture immediately after onCreateTexture accepted the slot, to decide whether the creation is an allocation an observer counts, both when it is created and when it is released. The answer must therefore already hold when onCreateTexture returns. The default is true: every texture a backend holds is one it created. A backend that can also name memory belonging to someone else - a registration of a host-owned object, say - overrides this and says which is which.
| slotIndex | Validated live texture slot. |
Reimplemented in donner::geode::GeodeWgpuAdapterDevice, and donner::gpu::vulkan::VulkanDevice.
|
inlineprotectedvirtual |
One nonblocking backend event iteration before a pending-destroy scan. Native devices report completion directly; callback-driven adapters override this hook.
Reimplemented in donner::geode::GeodeWgpuAdapterDevice.
|
protectedvirtual |
Backend hook: present the acquired texture.
| slotIndex | Slot of the surface. |
Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: name another device's exported texture in slotIndex.
Called only after the runtime has matched backing's device identity against backendDeviceIdentity, so a backend may treat backing as its own export type. The backend must hold the native object until onDestroyResource for the slot, and must not report it as an allocation of this device.
| slotIndex | Slot the registration occupies. |
| backing | The producer backend's export. |
Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: a buffer handle was retired. Discard unsubmitted work, but keep native resources alive until onDestroyResource.
| slotIndex | Retired buffer slot. |
Reimplemented in donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: a texture handle was retired. Discard unsubmitted work, but keep native resources alive until onDestroyResource.
| slotIndex | Retired texture slot. |
Reimplemented in donner::gpu::metal::MetalDevice.
|
protectedpure virtual |
Backend hook: validated command buffers were submitted as one submission.
The span holds at least one buffer and they execute in the order given. The backend owes the caller one completion for the whole span: whatever native objects it splits the work across, completedSerial reaches submissionSerial only once all of them have finished, and a backend that reports the submission accepted has accepted all of it.
| submissionSerial | Serial assigned to this submission. |
| commandBuffers | Command buffers of this submission, in execution order. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: onSubmit for a submission that must also wait on the device, before any of its work runs, for producer work it names through registrations ordered on the device (SourceOrdering::WaitOnDevice).
Every serial in waits is one its producer has handed to its native queue, and each backing appears once, with the latest serial it needs.
The default passes a submission with no waits to onSubmit and refuses one with waits. Only a backend whose exports report SourceOrdering::WaitOnDevice receives waits, since a registration's producer always belongs to the consumer's own backend, and that backend overrides this.
| submissionSerial | Serial assigned to this submission. |
| commandBuffers | Command buffers of this submission, in execution order. |
| waits | Producer work the submission waits for on the device; empty when there is none. |
Reimplemented in donner::gpu::metal::MetalDevice.
|
protectedvirtual |
Backend hook: what a surface supports.
| slotIndex | Slot of the surface. |
Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: the bytes the write onWriteTexture just accepted handed the backend's queue, which DeviceObserver::onTextureWritten reports.
Asked only when an observer is installed, immediately after onWriteTexture returned success. The default is the caller's whole span; a backend that repacks the rows before uploading reports the repacked size.
| data | The caller's span. |
Reimplemented in donner::geode::GeodeWgpuAdapterDevice.
|
nodiscardprotectedvirtual |
Backend hook: whether the write writeTexture just accepted for slotIndex is waiting for this device's next submission, rather than complete or ordered on the queue already.
Asked only for an exported texture. The default, false, is right for a backend whose writes either finish before returning or are ordered on the one queue every consumer shares.
| slotIndex | Validated live texture slot. |
Reimplemented in donner::gpu::metal::MetalDevice.
|
protectedvirtual |
Backend hook: release a mapping.
| mappingSlotIndex | Slot of the mapping. |
Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: waitForSerial with a budget already clamped to zero or more.
The default rechecks completedSerial until the budget runs out, resting between checks, which is what a backend whose completions arrive on their own thread needs and nothing more. A backend that can block on a completion signal, or that knows it has failed terminally, overrides this.
| serial | Submission serial to wait for. |
| timeoutSeconds | Longest to wait, in seconds; already clamped to a usable range. |
serial. Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: waitForSerialUnlessStalled with a bound already clamped.
The default, for a backend with no notion of progress, waits for serial for at most stallBound in all and reports a wait that ran out as stalled. A backend that tracks progress overrides this, together with onLastProgress.
| serial | Submission serial to wait for. |
| stallBound | Longest the work may go without progress. |
Reimplemented in donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedvirtual |
Backend hook: wait up to sliceSeconds for a pending mapping, and report what it found and how it spent the slice.
The runtime owns the deadline and the caller's cancellation; this reports only the mapping.
| mappingSlotIndex | Slot of the pending mapping. |
| sliceSeconds | Longest this call may block. |
Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a validated buffer write.
| slotIndex | Destination buffer slot. |
| offsetBytes | Destination byte offset. |
| data | Payload bytes. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
protectedpure virtual |
Backend hook: a validated texture write. The written rectangle is writeSize texels wide and tall with its top-left texel at destinationOrigin; texels outside it keep their contents.
| slotIndex | Destination texture slot. |
| data | Payload bytes. |
| dataLayout | Row layout of data. |
| writeSize | Extent written in texels. |
| destinationOrigin | Top-left texel of the written rectangle. |
Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.
|
nodiscard |
Whether texture names backing this device allocated, rather than memory some other owner holds and this device only named.
False for a null, stale, or foreign handle, so this answers "may I take this texture's allocation over?" rather than "does this handle resolve?". It is also false for a frame acquired from a surface: the presentation surface hands that texture out and takes it back, and a caller that freed it would free memory the swapchain still owns.
| texture | Handle to inspect; its device and generation are validated first. |
| void donner::gpu::Device::poll | ( | ) |
Processes deferred destructions: releases the backend object of every destroyed resource whose last referencing submission has completed (completedSerial), and recycles its slot.
Called opportunistically by destroy* and submit; call it directly after waiting for completion to reclaim resources promptly. A backend that delivers completion callbacks only while polled drives one nonblocking backend iteration before reclaiming slots.
| Result< MapSliceReport > donner::gpu::Device::pollMapping | ( | const BufferMapping & | mapping | ) |
Polls a mapping once without blocking or yielding; ready mappings become readable.
| mapping | Live mapping owned by this device. |
| Result< SurfaceStatus > donner::gpu::Device::presentSurface | ( | const Surface & | surface | ) |
Presents the texture acquired from surface and invalidates it.
Where the host drives its own frame loop, as a browser does for a canvas, the frame appears when the host shows it: presenting there hands the acquired texture back for that implicit presentation and submits nothing of its own. A frame that should not be shown ends through abandonCurrentTexture instead.
| surface | Live surface with an acquired texture. |
| Result< Texture > donner::gpu::Device::registerTexture | ( | const TextureExport & | source | ) |
Registers a texture another runtime device exported, as a read-only texture of this one.
Runs on this device's thread and reads only source, never the producer device. The registration describes the texture as the producer does, except that its usage is limited to TextureUsage::Sampled and TextureUsage::CopySrc: a consumer reads what the producer wrote and never writes it. It never owns the allocation (ownsTextureBacking is false) but holds it until this device recycles the registration's slot, which is after the last of this device's submissions naming it has completed.
Work this device submits that names the registration is ordered after every submission the producer had made referencing the texture before this call, and after the queued writes those submissions carried. On a backend whose devices do not share one native queue, either the backend orders such work on the device (SourceOrdering::WaitOnDevice) for a producer that shares this device's loss condition, so submit accepts it once the producer has handed that work to its queue and the work waits on the device, or submit refuses it until that producer work has completed. Either way waitForTextureSource is the host's bounded wait until the work may be submitted.
Refused with GpuErrorType::InvalidHandle for an empty token or one whose producer has released its handle; GpuErrorType::InvalidState for this device's own export or while a producer write to the texture is queued and not yet submitted; GpuErrorType::DeviceMismatch for another backend or native device; GpuErrorType::UsageMismatch when the texture can be neither sampled nor copied from; GpuErrorType::DeviceLost when either device is lost; and GpuErrorType::Unsupported by a backend that cannot name another device's textures.
| source | Token from the producer's exportTexture. |
| void donner::gpu::Device::removeObserver | ( | const DeviceObserver & | observer | ) |
Removes observer when it is the installed one and otherwise changes nothing, so an owner can only ever remove its own.
| observer | Observer its owner installed. |
|
inlinevirtual |
Shader representation accepted by this device. Recording and WebGPU devices use WGSL; native backends override this so callers select the matching build-time artifact.
Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.
|
nodiscard |
Bytes of this device's exported textures that are still held by an export token or a registration after this device released its own handle.
That memory is still resident, and no other device counts it as its allocation, so a working set measured from allocation accounting alone would miss it. Readable from any thread. The gauge belongs to this device: bytes still held after this device is destroyed are counted in a gauge nothing reads any more, so a holder that outlives its producer device is a working-set blind spot.
| Result< uint64_t > donner::gpu::Device::submit | ( | CommandBuffer | commandBuffer | ) |
Submits a finished command buffer, consuming it, and returns the assigned submission serial.
Serials start at 1 and increase by 1 per submission; a submission rejected here or by the backend does not consume a serial.
Every resource a recorded command references - including bind-group entry resources and the textures behind attachment and entry views - is re-validated against its recorded (slot, generation) identity, so a resource destroyed between recording and submission fails closed with GpuErrorType::InvalidHandle instead of reaching a backend. On success those resources are marked in-use by the new serial, which defers their backend destruction until the submission completes.
A buffer with an open mapping is refused with GpuErrorType::InvalidState, and the command buffer is consumed either way, so the work is recorded again after unmapBuffer. This covers uses that only read the buffer as well: the mapped range aliases the buffer's own storage, and a reader cannot tell which parts of it a submission will touch, so the buffer belongs either to the host or to the device and not to both at once.
| commandBuffer | Command buffer to submit; consumed even on failure. |
| Result< uint64_t > donner::gpu::Device::submit | ( | std::span< CommandBuffer > | commandBuffers | ) |
Submits finished command buffers as one submission, consuming them, and returns the single assigned submission serial.
The buffers execute in the order they appear in commandBuffers, and the whole span is one backend submission with one completion: a caller that records a frame through several independently-owned encoders keeps the frame's ordering and its single completion without reaching a queue per encoder. Splitting a frame across buffers is therefore free to follow whatever bound a backend needs - a very large single command buffer stalls the Metal completion path - without changing what a frame costs on the queue.
A span holds between one and kMaxCommandBuffersPerSubmission buffers. Both size refusals carry GpuErrorType::InvalidDescriptor and are decided before anything is consumed, so the caller still owns its buffers: an empty span names no work and would consume a serial nothing can wait on, and an oversized one is refused rather than submitted so the caller splits it across submissions instead.
Once consumption starts every buffer is consumed, including after a refusal, so a span that was refused partway cannot be submitted again with the accepted part already gone. Refusals otherwise carry the same meanings as the single-buffer overload.
| commandBuffers | Command buffers to submit in execution order; every element is consumed, leaving the caller's handles null, unless the span's size refuses it outright. |
|
inlinevirtual |
Whether indexed draws through this device honor every value of format. Metal and WebGPU always do; a Vulkan device without fullDrawIndexUint32 caps 32-bit indices below the full range, and RenderPassEncoder::setIndexBuffer refuses that format on it rather than let a driver truncate index values.
| format | Index format to query. |
Reimplemented in donner::gpu::vulkan::VulkanDevice.
| Result< SurfaceCapabilities > donner::gpu::Device::surfaceCapabilities | ( | const Surface & | surface | ) | const |
What surface supports, for choosing a configuration.
| surface | Live surface. |
| Result< TextureDescriptor > donner::gpu::Device::textureDescriptor | ( | const Texture & | texture | ) | const |
Returns the descriptor texture was created with, by value.
This is what the device itself validated the texture against, so a caller reading its extent, format or capabilities from here cannot describe the texture differently than the device does. Null, foreign-device, and stale handles fail with the same resource errors as other texture operations, which makes this also the answer to "does this handle still name a texture of mine?".
| texture | Live texture owned by this device. |
|
protected |
Last accepted submission referencing a texture slot already validated by the caller.
| slotIndex | A validated live texture slot. |
| Status donner::gpu::Device::unmapBuffer | ( | BufferMapping && | mapping | ) |
Releases a mapping, invalidating the handle and every copy of it.
| mapping | Mapping to release; consumed either way (see the destroy contract above). |
Validates a buffer handle for backend-provided auxiliary entry points (test readback helpers and similar), running the same null/device-identity/generation checks the template-method public API performs before its hooks.
| buffer | Handle to validate. |
|
protected |
Validates a buffer-mapping handle for backend-provided auxiliary entry points, running the same null/device-identity/generation checks the template-method public API performs, so a stale handle cannot read state belonging to the slot's new occupant.
| mapping | Handle to validate. |
|
protected |
Validates a texture handle for backend-provided auxiliary entry points, running the same null/device-identity/generation checks the template-method public API performs.
| texture | Handle to validate. |
|
protected |
| Result< MapWaitReport > donner::gpu::Device::waitForMapping | ( | const BufferMapping & | mapping, |
| const MapWaitParams & | params, | ||
| const std::function< bool()> & | shouldCancel, | ||
| const MapWaitTestHooks & | testHooks = {} ) |
Waits for a pending mapping in slices, until it completes, the caller stops it, the budget runs out, or the device is lost.
shouldCancel is consulted before each slice, so a caller that changes its mind stops within one slice rather than at the end of the budget. Device loss ends the wait immediately: the mapping can never complete afterwards, and reporting it as a timeout would describe a permanent failure as a slow one.
Destroying the mapped buffer is reported by where the wait was when it happened: a buffer already gone when the wait starts fails the call with GpuErrorType::InvalidHandle, while one destroyed during the wait ends it with MapWaitOutcome::Failed, because by then the call has a wait to report the outcome of rather than a handle to reject.
The report carries how the backend spent the wait alongside how it ended, because a wait that blocked on the map's completion signal and one that polled for it take wall times orders of magnitude apart, and only the backend knows which it did.
| mapping | Live mapping of this device. |
| params | Slice length and total budget; both must be greater than zero. |
| shouldCancel | Consulted before each slice; may be empty for an uncancellable wait. |
| testHooks | Optional clock/rest hooks for deterministic tests; production passes none. |
| bool donner::gpu::Device::waitForSerial | ( | uint64_t | serial, |
| double | timeoutSeconds ) |
Blocks until completedSerial reaches serial, timeoutSeconds elapses, or the backend gives up on the work, and reports whether the submission completed.
The budget is the caller's and it is always bounded: a wait never outlives it, so a driver that stops answering costs one deadline rather than the process. A backend that can tell it has failed terminally returns false at once instead of spending the budget, because no submission can complete afterwards and reporting that as a timeout would describe a permanent failure as a slow one.
A false return is therefore "not completed, and not within this budget", never "completed but unreadable"; a caller that needs to tell a timeout from a dead device asks the backend which it was.
| serial | Submission serial to wait for. |
| timeoutSeconds | Longest to wait, in seconds; clamped to the range zero to kMaxWaitSeconds, so a budget of zero reports what is already known without blocking. |
serial. | SerialWaitResult donner::gpu::Device::waitForSerialUnlessStalled | ( | uint64_t | serial, |
| std::chrono::milliseconds | stallBound ) |
Blocks until completedSerial reaches serial, giving up only when the work the serial waits behind stops making progress.
A serial completes only after everything queued ahead of it, so a fixed budget measures the whole backlog and would time out a slow device that is still working through it. This wait gives up instead once lastProgress is stallBound in the past. The bound runs from the last progress, not from the start of the wait, so a new wait on work that has already stopped does not restart it. While progress continues the wait has no total limit: the work ahead of a serial is finite, and a stall anywhere in it ends the wait within the bound. A backend with no notion of progress (lastProgress returns nothing) bounds the whole wait by stallBound instead.
A lost root, or a backend failure that means the serial can never complete, ends the wait at once with SerialWaitEnd::Failed. Declares nothing: what a stall means is the caller's decision. Owner-thread only.
| serial | Submission serial to wait for. |
| stallBound | Longest the work may go without progress; clamped to the range zero to kMaxWaitSeconds. |
| bool donner::gpu::Device::waitForTextureSource | ( | const Texture & | registration, |
| double | timeoutSeconds ) |
Waits until work naming registration may be submitted, the budget runs out, or either device is lost, and reports whether it may.
Work may be submitted once the producer work the registration is ordered after has completed. Returns true at once for a texture this device allocated and for a registration whose producer shares this device's native queue, because submission order already orders them, and for a registration ordered on the device as soon as its producer has handed that work to its queue, because the device then orders it. A registration is ordered on the device only when its producer shares this device's loss condition: the device-side wait ends however the producer's work ends, and only a shared condition carries a failure or loss there to this device. A wait that spends its budget declares nothing, like waitForSerial; the caller's deadline is its own policy. A producer whose backend reports a terminal execution failure is declared lost with no wait site, because the backend reported it and no deadline expired.
| registration | Live texture of this device. |
| timeoutSeconds | Longest to wait, in seconds; clamped like waitForSerial. |
| SerialWaitResult donner::gpu::Device::waitForTextureSourceUnlessStalled | ( | const Texture & | registration, |
| std::chrono::milliseconds | stallBound ) |
waitForTextureSource for a caller whose bound exists to detect a hung producer: the wait gives up only once the producer has made no progress for stallBound, measured from that progress, rather than giving the producer's whole backlog a fixed budget.
A producer whose backend does not report progress (SubmissionCompletion::lastProgress) bounds the whole wait by stallBound instead. Declares nothing.
| registration | Live texture of this device. |
| stallBound | Longest the producer may go without progress; clamped like waitForSerialUnlessStalled. |
| Status donner::gpu::Device::writeBuffer | ( | const Buffer & | buffer, |
| uint64_t | offsetBytes, | ||
| std::span< const uint8_t > | data ) |
Writes data into buffer at offsetBytes.
Fails closed if the range does not fit (checked arithmetic) or the buffer lacks BufferUsage::CopyDst.
A write never changes bytes an already submitted command still reads, and for the same reason never changes bytes the host is reading: a buffer with an open mapping is refused with GpuErrorType::InvalidState until unmapBuffer releases it.
MetalDevice and VulkanDevice copy busy-buffer writes with four-byte-aligned offsets and sizes into a bounded queue, flushed before the next ordinary submission, including an empty command stream. Unaligned writes wait for that buffer's outstanding work and return GpuErrorType::InvalidState if the bounded wait times out. On VulkanDevice, a wait that ends because another device over the same root declared it lost returns GpuErrorType::DeviceLost instead. Queued writes can fail with GpuErrorType::LimitExceeded when their staging budget is exhausted. Callers must handle these errors without assuming a failed write changed the buffer.
| buffer | Destination buffer. |
| offsetBytes | Destination byte offset. |
| data | Payload bytes. |
| Status donner::gpu::Device::writeTexture | ( | const Texture & | texture, |
| std::span< const uint8_t > | data, | ||
| const TexelCopyBufferLayout & | dataLayout, | ||
| const Extent2d & | writeSize, | ||
| const Origin2d & | destinationOrigin = {} ) |
Writes texel rows from data into the writeSize rectangle of texture whose top-left texel is destinationOrigin, leaving every texel outside that rectangle unchanged.
The origin defaults to texel (0, 0), the whole-rect-from-the-origin convention this operation had before sub-rectangle writes existed, so an existing call keeps its meaning.
Fails closed unless the texture has TextureUsage::CopyDst, dataLayout is 256-aligned and covers writeSize, destinationOrigin plus writeSize fits inside the texture, and the described rows fit inside data (all checked arithmetic).
On VulkanDevice, when another device over the same root declared it lost and this device has no error of its own, a write returns GpuErrorType::DeviceLost without starting an upload, as does an upload whose wait that declaration ends. A device with an error of its own, a driver-reported loss included, returns that error as GpuErrorType::InvalidState.
| texture | Destination texture. |
| data | Payload bytes laid out per dataLayout. |
| dataLayout | Row layout of data. |
| writeSize | Extent to write in texels. |
| destinationOrigin | Top-left texel of the written rectangle. |
|
staticconstexpr |
Most command buffers one submission may carry.
A backend acquires a native command buffer per element and commits none of them until the whole span has encoded, so that nothing reaches the queue when an element fails to encode. Native queues cap how many command buffers may be outstanding at once and block the acquiring thread at that cap, so a span large enough to reach it on its own would wait for buffers only it could release.
This is the refusal bound, not a promise that every smaller span clears that cap on every backend: the cap belongs to the native queue, and a backend layered over another API can sit far below this one. A caller splitting a frame picks a bound its backend tolerates and stays under it; this bound only keeps a span from being absurd.