Donner SVG 0.8.0
0.8.0 ยท ebf353960.8.0 main
SVG editor and embeddable C⁠+⁠+⁠20 engine.
Loading...
Searching...
No Matches
donner::gpu::Device Class Referenceabstract

Abstract GPU device: resource creation, queue writes, and submission with shared fail-closed validation. More...

#include "donner/gpu/Device.h"

Inheritance diagram for donner::gpu::Device:
[legend]

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 &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.
SerialWaitResult 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.
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 &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.
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

Detailed Description

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.

Examples
geode_embed.cc.

Class Documentation

◆ donner::gpu::Device::MapWaitTestHooks

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.

Class Members
function< time_point()> now Clock the budget is measured against. Defaults to std::chrono::steady_clock::now.
function< void(microseconds)> rest Rests for the given duration. Defaults to std::this_thread::sleep_for.

Member Function Documentation

◆ abandonCurrentTexture()

Status donner::gpu::Device::abandonCurrentTexture ( const Surface & surface)

Releases the acquired texture of surface without presenting it, for a frame the caller decided not to show.

Parameters
surfaceLive surface with an acquired texture.
Examples
geode_embed.cc.

◆ acquireCurrentTexture()

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.

Parameters
surfaceLive, configured surface.
Examples
geode_embed.cc.

◆ adoptLostState()

void donner::gpu::Device::adoptLostState ( std::shared_ptr< DeviceLostState > state)
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.

Parameters
stateCondition to share; ignored when null, so a backend may pass an absent one.

◆ backendDeviceIdentity()

virtual BackendDeviceIdentity donner::gpu::Device::backendDeviceIdentity ( ) const
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.

◆ bufferLastUseSerial()

uint64_t donner::gpu::Device::bufferLastUseSerial ( uint32_t slotIndex) const
protected

Last accepted submission referencing a buffer slot already validated by the caller.

Parameters
slotIndexA validated live buffer slot.

◆ completedSerial()

virtual uint64_t donner::gpu::Device::completedSerial ( ) const
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.

◆ configureSurface()

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.

Parameters
surfaceLive surface.
configurationFormat, usage, extent, pacing and alpha compositing.
Examples
geode_embed.cc.

◆ createBindGroup()

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.

Parameters
descriptorValidated bind group descriptor.

◆ createBindGroupLayout()

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.

Parameters
descriptorValidated layout descriptor.

◆ createBuffer()

Result< Buffer > donner::gpu::Device::createBuffer ( const BufferDescriptor & descriptor)

Creates a buffer.

Fails closed on zero or oversized byteSize or empty usage.

Parameters
descriptorValidated buffer descriptor.

◆ createComputePipeline()

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.

Parameters
descriptorValidated pipeline descriptor.

◆ createPipelineLayout()

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.

Parameters
descriptorValidated pipeline layout descriptor.

◆ createRenderPipeline()

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.

Parameters
descriptorValidated pipeline descriptor.

◆ createSampler()

Result< Sampler > donner::gpu::Device::createSampler ( const SamplerDescriptor & descriptor)

Creates a sampler.

Parameters
descriptorValidated sampler descriptor.

◆ createShaderModule()

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.

Parameters
descriptorValidated shader module descriptor.

◆ createSurface()

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.

Parameters
descriptorLabel and platform object to present to.
Examples
geode_embed.cc.

◆ createTexture()

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.

Parameters
descriptorValidated texture descriptor.

◆ createTextureView()

Result< TextureView > donner::gpu::Device::createTextureView ( const Texture & texture,
const TextureViewDescriptor & descriptor )

Creates a view of texture covering the whole texture.

Parameters
textureTexture to view; must be a live handle of this device.
descriptorValidated view descriptor.

◆ destroyBindGroup()

Status donner::gpu::Device::destroyBindGroup ( BindGroup && bindGroup)

Destroys a bind group (see the destroy contract above).

Parameters
bindGroupHandle to destroy.

◆ destroyBindGroupLayout()

Status donner::gpu::Device::destroyBindGroupLayout ( BindGroupLayout && bindGroupLayout)

Destroys a bind group layout (see the destroy contract above).

Parameters
bindGroupLayoutHandle to destroy.

◆ destroyBuffer()

Status donner::gpu::Device::destroyBuffer ( Buffer && buffer)

Destroys a buffer (see the destroy contract above).

Parameters
bufferHandle to destroy.

◆ destroyBufferBacking()

Status donner::gpu::Device::destroyBufferBacking ( Buffer && buffer)

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.

Warning
Releasing now is only safe once no unfinished submission still reads the buffer, which is a fact only the caller has: the ordinary destroyBuffer defers the release until the last submission naming the resource completes, and this operation gives that up in exchange for reclaiming the memory immediately. Callers satisfy it by construction - a cancelled map has no submission left to finish, and a pooled entry is idle before it can be evicted.

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.

Parameters
bufferLive buffer handle of this device; consumed either way.

◆ destroyComputePipeline()

Status donner::gpu::Device::destroyComputePipeline ( ComputePipeline && computePipeline)

Destroys a compute pipeline (see the destroy contract above).

Parameters
computePipelineHandle to destroy.

◆ destroyPipelineLayout()

Status donner::gpu::Device::destroyPipelineLayout ( PipelineLayout && pipelineLayout)

Destroys a pipeline layout (see the destroy contract above).

Parameters
pipelineLayoutHandle to destroy.

◆ destroyRenderPipeline()

Status donner::gpu::Device::destroyRenderPipeline ( RenderPipeline && renderPipeline)

Destroys a render pipeline (see the destroy contract above).

Parameters
renderPipelineHandle to destroy.

◆ destroySampler()

Status donner::gpu::Device::destroySampler ( Sampler && sampler)

Destroys a sampler (see the destroy contract above).

Parameters
samplerHandle to destroy.

◆ destroyShaderModule()

Status donner::gpu::Device::destroyShaderModule ( ShaderModule && shaderModule)

Destroys a shader module (see the destroy contract above).

Parameters
shaderModuleHandle to destroy.

◆ destroySurface()

Status donner::gpu::Device::destroySurface ( Surface && surface)

Destroys a surface (see the destroy contract above).

Parameters
surfaceHandle to destroy.

◆ destroyTexture()

Status donner::gpu::Device::destroyTexture ( Texture && texture)

Destroys a texture (see the destroy contract above).

Parameters
textureHandle to destroy.

◆ destroyTextureBacking()

Status donner::gpu::Device::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.

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.

Parameters
textureLive texture handle of this device; consumed either way.

◆ destroyTextureView()

Status donner::gpu::Device::destroyTextureView ( TextureView && textureView)

Destroys a texture view (see the destroy contract above).

Parameters
textureViewHandle to destroy.

◆ deviceLostReason()

virtual RcString donner::gpu::Device::deviceLostReason ( ) const
inlinevirtual

Backend-provided loss reason, when the backend retains one. Empty otherwise.

Reimplemented in donner::gpu::browser::BrowserDevice.

◆ exportTexture()

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.

Parameters
textureLive texture of this device.

◆ installObserver()

Status donner::gpu::Device::installObserver ( DeviceObserver & observer)
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.

Parameters
observerObserver to notify.

◆ isLost()

bool donner::gpu::Device::isLost ( ) const
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.

◆ lastProgress()

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.

◆ lastTextureUseSerial()

uint64_t donner::gpu::Device::lastTextureUseSerial ( uint32_t textureSlotIndex) const
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.

Parameters
textureSlotIndexSlot of the texture.

◆ mapBufferAsync()

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.

Parameters
bufferBuffer to map; needs BufferUsage::MapRead.
modeHow the host will access the range.
offsetBytesByte offset of the mapped range.
byteCountLength of the mapped range; must be nonzero and fit the buffer.

◆ mappedBytes()

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.

Parameters
mappingLive, completed mapping of this device.

◆ markLostAfterWaitTimeout()

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.

Parameters
siteWhich bounded wait gave up.
elapsedWall time that wait spent before giving up.
reasonHuman-readable cause, logged once.

◆ onAbandonCurrentTexture()

virtual void donner::gpu::Device::onAbandonCurrentTexture ( uint32_t slotIndex)
protectedvirtual

Backend hook: drop the acquired texture without presenting.

Parameters
slotIndexSlot of the surface.

Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onAcquireCurrentTexture()

virtual Result< SurfaceStatus > donner::gpu::Device::onAcquireCurrentTexture ( uint32_t slotIndex,
uint32_t textureSlotIndex )
protectedvirtual

Backend hook: acquire the next frame's texture and report the surface's state.

Parameters
slotIndexSlot of the surface.
textureSlotIndexSlot the runtime allocated for the acquired texture.

Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onConfigureSurface()

virtual Status donner::gpu::Device::onConfigureSurface ( uint32_t slotIndex,
const SurfaceConfiguration & configuration )
protectedvirtual

Backend hook: apply a configuration.

Parameters
slotIndexSlot of the surface.
configurationConfiguration to apply.

Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreateBindGroup()

virtual Status donner::gpu::Device::onCreateBindGroup ( uint32_t slotIndex,
const BindGroupDescriptor & descriptor )
protectedpure virtual

Backend hook: a bind group passed validation and occupies slotIndex.

Parameters
slotIndexSlot index of the new resource.
descriptorValidated descriptor.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreateBindGroupLayout()

virtual Status donner::gpu::Device::onCreateBindGroupLayout ( uint32_t slotIndex,
const BindGroupLayoutDescriptor & descriptor )
protectedpure virtual

Backend hook: a bind group layout passed validation and occupies slotIndex.

Parameters
slotIndexSlot index of the new resource.
descriptorValidated descriptor.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreateBuffer()

virtual Status donner::gpu::Device::onCreateBuffer ( uint32_t slotIndex,
const BufferDescriptor & descriptor )
protectedpure virtual

Backend hook: a buffer passed validation and occupies slotIndex.

Parameters
slotIndexSlot index of the new resource.
descriptorValidated descriptor.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreateComputePipeline()

virtual Status donner::gpu::Device::onCreateComputePipeline ( uint32_t slotIndex,
const ComputePipelineDescriptor & descriptor )
protectedpure virtual

Backend hook: a compute pipeline passed validation and occupies slotIndex.

Parameters
slotIndexSlot index of the new resource.
descriptorValidated descriptor.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreatePipelineLayout()

virtual Status donner::gpu::Device::onCreatePipelineLayout ( uint32_t slotIndex,
const PipelineLayoutDescriptor & descriptor )
protectedpure virtual

Backend hook: a pipeline layout passed validation and occupies slotIndex.

Parameters
slotIndexSlot index of the new resource.
descriptorValidated descriptor.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreateRenderPipeline()

virtual Status donner::gpu::Device::onCreateRenderPipeline ( uint32_t slotIndex,
const RenderPipelineDescriptor & descriptor )
protectedpure virtual

Backend hook: a render pipeline passed validation and occupies slotIndex.

Parameters
slotIndexSlot index of the new resource.
descriptorValidated descriptor.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreateSampler()

virtual Status donner::gpu::Device::onCreateSampler ( uint32_t slotIndex,
const SamplerDescriptor & descriptor )
protectedpure virtual

Backend hook: a sampler passed validation and occupies slotIndex.

Parameters
slotIndexSlot index of the new resource.
descriptorValidated descriptor.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreateShaderModule()

virtual Status donner::gpu::Device::onCreateShaderModule ( uint32_t slotIndex,
const ShaderModuleDescriptor & descriptor )
protectedpure virtual

Backend hook: a shader module passed validation and occupies slotIndex.

Parameters
slotIndexSlot index of the new resource.
descriptorValidated descriptor.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreateSurface()

virtual Status donner::gpu::Device::onCreateSurface ( uint32_t slotIndex,
const SurfaceDescriptor & descriptor )
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.

Parameters
slotIndexSlot the surface occupies.
descriptorLabel and platform object.

Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreateTexture()

virtual Status donner::gpu::Device::onCreateTexture ( uint32_t slotIndex,
const TextureDescriptor & descriptor )
protectedpure virtual

Backend hook: a texture passed validation and occupies slotIndex.

Parameters
slotIndexSlot index of the new resource.
descriptorValidated descriptor.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onCreateTextureView()

virtual Status donner::gpu::Device::onCreateTextureView ( uint32_t slotIndex,
uint32_t textureSlotIndex,
const TextureViewDescriptor & descriptor )
protectedpure virtual

Backend hook: a texture view passed validation and occupies slotIndex.

Parameters
slotIndexSlot index of the new resource.
textureSlotIndexSlot index of the viewed texture.
descriptorValidated descriptor.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onDestroyBufferBacking()

virtual void donner::gpu::Device::onDestroyBufferBacking ( uint32_t slotIndex)
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.

Parameters
slotIndexValidated live buffer slot.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice.

◆ onDestroyResource()

virtual void donner::gpu::Device::onDestroyResource ( std::string_view resourceName,
uint32_t slotIndex )
protectedpure virtual

Backend hook: a retired resource is no longer used by submitted work and can be released.

Parameters
resourceNameResource type name, e.g. "buffer".
slotIndexSlot 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.

◆ onDestroySurface()

virtual void donner::gpu::Device::onDestroySurface ( uint32_t slotIndex)
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.

Parameters
slotIndexSlot of the surface.

Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onDestroyTextureBacking()

virtual void donner::gpu::Device::onDestroyTextureBacking ( uint32_t slotIndex)
protectedvirtual

Backend hook: the texture counterpart of onDestroyBufferBacking, with the same default. A slot whose backing this device does not own keeps its allocation.

Parameters
slotIndexValidated live texture slot.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice.

◆ onExportTexture()

virtual Result< BackendTextureExport > donner::gpu::Device::onExportTexture ( uint32_t slotIndex)
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.

Parameters
slotIndexValidated live texture slot.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onLastProgress()

virtual std::optional< std::chrono::steady_clock::time_point > donner::gpu::Device::onLastProgress ( )
protectedvirtual

Backend hook: lastProgress. The default reports no notion of progress.

Reimplemented in donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onMapBufferAsync()

virtual Status donner::gpu::Device::onMapBufferAsync ( uint32_t mappingSlotIndex,
uint32_t bufferSlotIndex,
MapMode mode,
uint64_t offsetBytes,
uint64_t byteCount )
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.

Parameters
mappingSlotIndexSlot the mapping occupies.
bufferSlotIndexSlot of the buffer being mapped.
modeHow the host will access the range.
offsetBytesByte offset of the mapped range.
byteCountLength of the mapped range.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onMappedBytes()

virtual Result< std::span< const uint8_t > > donner::gpu::Device::onMappedBytes ( uint32_t mappingSlotIndex) const
protectedvirtual

Backend hook: bytes of a completed mapping.

Parameters
mappingSlotIndexSlot of the mapping.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onOwnsTextureBacking()

virtual bool donner::gpu::Device::onOwnsTextureBacking ( uint32_t slotIndex) const
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.

Parameters
slotIndexValidated live texture slot.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onPollBackend()

virtual void donner::gpu::Device::onPollBackend ( )
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.

◆ onPresentSurface()

virtual Result< SurfaceStatus > donner::gpu::Device::onPresentSurface ( uint32_t slotIndex)
protectedvirtual

Backend hook: present the acquired texture.

Parameters
slotIndexSlot of the surface.

Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onRegisterTexture()

virtual Status donner::gpu::Device::onRegisterTexture ( uint32_t slotIndex,
const ExportedTextureBacking & backing )
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.

Parameters
slotIndexSlot the registration occupies.
backingThe producer backend's export.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onRetireBuffer()

virtual void donner::gpu::Device::onRetireBuffer ( uint32_t slotIndex)
protectedvirtual

Backend hook: a buffer handle was retired. Discard unsubmitted work, but keep native resources alive until onDestroyResource.

Parameters
slotIndexRetired buffer slot.

Reimplemented in donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onRetireTexture()

virtual void donner::gpu::Device::onRetireTexture ( uint32_t slotIndex)
protectedvirtual

Backend hook: a texture handle was retired. Discard unsubmitted work, but keep native resources alive until onDestroyResource.

Parameters
slotIndexRetired texture slot.

Reimplemented in donner::gpu::metal::MetalDevice.

◆ onSubmit()

virtual Status donner::gpu::Device::onSubmit ( uint64_t submissionSerial,
std::span< const SubmittedCommandBuffer > commandBuffers )
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.

Parameters
submissionSerialSerial assigned to this submission.
commandBuffersCommand 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.

◆ onSubmitAfterSources()

virtual Status donner::gpu::Device::onSubmitAfterSources ( uint64_t submissionSerial,
std::span< const SubmittedCommandBuffer > commandBuffers,
std::span< const SourceWait > waits )
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.

Parameters
submissionSerialSerial assigned to this submission.
commandBuffersCommand buffers of this submission, in execution order.
waitsProducer work the submission waits for on the device; empty when there is none.

Reimplemented in donner::gpu::metal::MetalDevice.

◆ onSurfaceCapabilities()

virtual Result< SurfaceCapabilities > donner::gpu::Device::onSurfaceCapabilities ( uint32_t slotIndex) const
protectedvirtual

Backend hook: what a surface supports.

Parameters
slotIndexSlot of the surface.

Reimplemented in donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onTextureWriteByteCount()

virtual uint64_t donner::gpu::Device::onTextureWriteByteCount ( std::span< const uint8_t > data) const
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.

Parameters
dataThe caller's span.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice.

◆ onTextureWritePending()

virtual bool donner::gpu::Device::onTextureWritePending ( uint32_t slotIndex) const
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.

Parameters
slotIndexValidated live texture slot.

Reimplemented in donner::gpu::metal::MetalDevice.

◆ onUnmapBuffer()

virtual void donner::gpu::Device::onUnmapBuffer ( uint32_t mappingSlotIndex)
protectedvirtual

Backend hook: release a mapping.

Parameters
mappingSlotIndexSlot of the mapping.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onWaitForSerial()

virtual bool donner::gpu::Device::onWaitForSerial ( uint64_t serial,
double timeoutSeconds )
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.

Parameters
serialSubmission serial to wait for.
timeoutSecondsLongest to wait, in seconds; already clamped to a usable range.
Returns
True once this device has completed serial.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onWaitForSerialUnlessStalled()

virtual SerialWaitResult donner::gpu::Device::onWaitForSerialUnlessStalled ( uint64_t serial,
std::chrono::milliseconds stallBound )
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.

Parameters
serialSubmission serial to wait for.
stallBoundLongest the work may go without progress.

Reimplemented in donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onWaitMappingSlice()

virtual MapSliceReport donner::gpu::Device::onWaitMappingSlice ( uint32_t mappingSlotIndex,
double sliceSeconds )
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.

Parameters
mappingSlotIndexSlot of the pending mapping.
sliceSecondsLongest this call may block.

Reimplemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onWriteBuffer()

virtual Status donner::gpu::Device::onWriteBuffer ( uint32_t slotIndex,
uint64_t offsetBytes,
std::span< const uint8_t > data )
protectedpure virtual

Backend hook: a validated buffer write.

Parameters
slotIndexDestination buffer slot.
offsetBytesDestination byte offset.
dataPayload bytes.

Implemented in donner::geode::GeodeWgpuAdapterDevice, donner::gpu::browser::BrowserDevice, donner::gpu::metal::MetalDevice, donner::gpu::RecordingDevice, and donner::gpu::vulkan::VulkanDevice.

◆ onWriteTexture()

virtual Status donner::gpu::Device::onWriteTexture ( uint32_t slotIndex,
std::span< const uint8_t > data,
const TexelCopyBufferLayout & dataLayout,
const Extent2d & writeSize,
const Origin2d & destinationOrigin )
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.

Parameters
slotIndexDestination texture slot.
dataPayload bytes.
dataLayoutRow layout of data.
writeSizeExtent written in texels.
destinationOriginTop-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.

◆ ownsTextureBacking()

bool donner::gpu::Device::ownsTextureBacking ( const Texture & texture) const
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.

Parameters
textureHandle to inspect; its device and generation are validated first.

◆ poll()

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.

◆ pollMapping()

Result< MapSliceReport > donner::gpu::Device::pollMapping ( const BufferMapping & mapping)

Polls a mapping once without blocking or yielding; ready mappings become readable.

Parameters
mappingLive mapping owned by this device.

◆ presentSurface()

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.

Parameters
surfaceLive surface with an acquired texture.
Examples
geode_embed.cc.

◆ registerTexture()

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.

Parameters
sourceToken from the producer's exportTexture.

◆ removeObserver()

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.

Parameters
observerObserver its owner installed.

◆ shaderSourceKind()

virtual ShaderSourceKind donner::gpu::Device::shaderSourceKind ( ) const
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.

◆ sharedTextureTailBytes()

uint64_t donner::gpu::Device::sharedTextureTailBytes ( ) const
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.

◆ submit() [1/2]

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.

Parameters
commandBufferCommand buffer to submit; consumed even on failure.

◆ submit() [2/2]

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.

Parameters
commandBuffersCommand buffers to submit in execution order; every element is consumed, leaving the caller's handles null, unless the span's size refuses it outright.

◆ supportsFullIndexRange()

virtual bool donner::gpu::Device::supportsFullIndexRange ( IndexFormat format) const
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.

Parameters
formatIndex format to query.

Reimplemented in donner::gpu::vulkan::VulkanDevice.

◆ surfaceCapabilities()

Result< SurfaceCapabilities > donner::gpu::Device::surfaceCapabilities ( const Surface & surface) const

What surface supports, for choosing a configuration.

Parameters
surfaceLive surface.
Examples
geode_embed.cc.

◆ textureDescriptor()

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?".

Parameters
textureLive texture owned by this device.

◆ textureLastUseSerial()

uint64_t donner::gpu::Device::textureLastUseSerial ( uint32_t slotIndex) const
protected

Last accepted submission referencing a texture slot already validated by the caller.

Parameters
slotIndexA validated live texture slot.

◆ unmapBuffer()

Status donner::gpu::Device::unmapBuffer ( BufferMapping && mapping)

Releases a mapping, invalidating the handle and every copy of it.

Parameters
mappingMapping to release; consumed either way (see the destroy contract above).

◆ validateBufferHandleForBackend()

Status donner::gpu::Device::validateBufferHandleForBackend ( const Buffer & buffer) const
protected

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.

Parameters
bufferHandle to validate.

◆ validateBufferMappingHandleForBackend()

Status donner::gpu::Device::validateBufferMappingHandleForBackend ( const BufferMapping & mapping) const
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.

Parameters
mappingHandle to validate.

◆ validateTextureHandleForBackend()

Status donner::gpu::Device::validateTextureHandleForBackend ( const Texture & texture) const
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.

Parameters
textureHandle to validate.

◆ validateTextureViewHandleForBackend()

Status donner::gpu::Device::validateTextureViewHandleForBackend ( const TextureView & textureView) const
protected

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.

Parameters
textureViewHandle to validate.

◆ waitForMapping()

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.

Parameters
mappingLive mapping of this device.
paramsSlice length and total budget; both must be greater than zero.
shouldCancelConsulted before each slice; may be empty for an uncancellable wait.
testHooksOptional clock/rest hooks for deterministic tests; production passes none.

◆ waitForSerial()

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.

Parameters
serialSubmission serial to wait for.
timeoutSecondsLongest to wait, in seconds; clamped to the range zero to kMaxWaitSeconds, so a budget of zero reports what is already known without blocking.
Returns
True once this device has completed serial.

◆ waitForSerialUnlessStalled()

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.

Parameters
serialSubmission serial to wait for.
stallBoundLongest the work may go without progress; clamped to the range zero to kMaxWaitSeconds.
Returns
How the wait ended, and how long it ran.

◆ waitForTextureSource()

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.

Parameters
registrationLive texture of this device.
timeoutSecondsLongest to wait, in seconds; clamped like waitForSerial.
Returns
True once work naming the registration may be submitted.

◆ waitForTextureSourceUnlessStalled()

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.

Parameters
registrationLive texture of this device.
stallBoundLongest the producer may go without progress; clamped like waitForSerialUnlessStalled.
Returns
Completed once work naming the registration may be submitted, Failed when a device is lost or the producer failed, Stalled when the producer stopped progressing.

◆ writeBuffer()

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.

Parameters
bufferDestination buffer.
offsetBytesDestination byte offset.
dataPayload bytes.

◆ writeTexture()

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.

Parameters
textureDestination texture.
dataPayload bytes laid out per dataLayout.
dataLayoutRow layout of data.
writeSizeExtent to write in texels.
destinationOriginTop-left texel of the written rectangle.

Member Data Documentation

◆ kMaxCommandBuffersPerSubmission

size_t donner::gpu::Device::kMaxCommandBuffersPerSubmission = 256
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.


The documentation for this class was generated from the following file: