|
| ShaderSourceKind | shaderSourceKind () const override |
| | Native shader representation accepted by this device.
|
|
bool | usesUnifiedMemoryForTest () const |
| | Whether this device's resources are built for unified memory. Test accessor.
|
| uint64_t | hostWritePublishCountForTest () const |
| | How many buffer writes have published their range to the device copy. Test accessor.
|
|
uint64_t | deviceWritePublishCountForTest () const |
| | How many submissions have published the device's changes back to the host copy. Test accessor, for the same reason as above but in the other direction.
|
|
WriteStats | writeStatsForTest () const |
| | Current queue-write counters. Does not wait or change device state.
|
|
Status | pauseSubmissionsForTest () |
| | Pauses submitted GPU work at a shared event until resumeSubmissionsForTest is called. A deterministic test seam for writes issued while an earlier submission is in flight.
|
|
void | resumeSubmissionsForTest () |
| | Releases the event installed by pauseSubmissionsForTest. Safe when no pause is active.
|
|
| ~MetalDevice () override |
| | Destructor; releases all Metal objects still alive.
|
| uint64_t | completedSerial () const override |
| | Serial of the most recent submission whose Metal command buffer has completed on the GPU (0 if none). Updated by completion handlers, which may run on another thread.
|
| bool | waitForSerial (uint64_t serial, double timeoutSeconds) |
| | Blocks until completedSerial reaches serial or timeoutSeconds elapses, by polling the completion counter (the completion handler runs on a Metal-internal thread, so a poll loop with a short sleep is sufficient and keeps this backend free of extra sync primitives).
|
| Result< std::vector< uint8_t > > | readBackBuffer (const Buffer &buffer) |
| | Copies the full contents of buffer back to the host and returns the bytes.
|
|
std::string | lastErrorForTest () const |
| | Message of the most recent asynchronous command-buffer execution error captured by a completion handler, or an empty string if none occurred. Test/diagnostic accessor.
|
|
std::string | adapterName () const |
| | Name the Metal driver reports for the underlying device, for example Apple M1 Pro. Two GPUs running the same shaders can round a covered edge texel differently, so anything comparing this backend's pixels against a committed record has to know which one it is on.
|
|
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.
|
| 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< 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).
|
|
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< MapWaitOutcome > | waitForMapping (const BufferMapping &mapping, const MapWaitParams ¶ms, const std::function< bool()> &shouldCancel, const MapWaitTestHooks &testHooks={}) |
| 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) |
| | Writes texel rows from data into texture starting at texel (0, 0).
|
| Result< uint64_t > | submit (CommandBuffer commandBuffer) |
| | Submits a finished command buffer, consuming it, and returns the 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.
|
|
uint64_t | lastSubmittedSerial () const |
| | Serial assigned to the most recent submission (0 if none yet).
|
|
| Status | onCreateBuffer (uint32_t slotIndex, const BufferDescriptor &descriptor) override |
| | Backend hook: a buffer passed validation and occupies slotIndex.
|
| Status | onCreateTexture (uint32_t slotIndex, const TextureDescriptor &descriptor) override |
| | Backend hook: a texture passed validation and occupies slotIndex.
|
| Status | onCreateTextureView (uint32_t slotIndex, uint32_t textureSlotIndex, const TextureViewDescriptor &descriptor) override |
| | Backend hook: a texture view passed validation and occupies slotIndex.
|
| Status | onCreateSampler (uint32_t slotIndex, const SamplerDescriptor &descriptor) override |
| | Backend hook: a sampler passed validation and occupies slotIndex.
|
| Status | onCreateBindGroupLayout (uint32_t slotIndex, const BindGroupLayoutDescriptor &descriptor) override |
| | Backend hook: a bind group layout passed validation and occupies slotIndex.
|
| Status | onCreateBindGroup (uint32_t slotIndex, const BindGroupDescriptor &descriptor) override |
| | Backend hook: a bind group passed validation and occupies slotIndex.
|
| Status | onCreatePipelineLayout (uint32_t slotIndex, const PipelineLayoutDescriptor &descriptor) override |
| | Backend hook: a pipeline layout passed validation and occupies slotIndex.
|
| Status | onCreateShaderModule (uint32_t slotIndex, const ShaderModuleDescriptor &descriptor) override |
| | Backend hook: a shader module passed validation and occupies slotIndex.
|
| Status | onCreateRenderPipeline (uint32_t slotIndex, const RenderPipelineDescriptor &descriptor) override |
| | Backend hook: a render pipeline passed validation and occupies slotIndex.
|
| Status | onCreateComputePipeline (uint32_t slotIndex, const ComputePipelineDescriptor &descriptor) override |
| | Backend hook: a compute pipeline passed validation and occupies slotIndex.
|
| void | onRetireBuffer (uint32_t slotIndex) override |
| | Backend hook: a buffer handle was retired. Discard unsubmitted work, but keep native resources alive until onDestroyResource.
|
| void | onRetireTexture (uint32_t slotIndex) override |
| | Backend hook: a texture handle was retired. Discard unsubmitted work, but keep native resources alive until onDestroyResource.
|
| void | onDestroyResource (std::string_view resourceName, uint32_t slotIndex) override |
| | Backend hook: a retired resource is no longer used by submitted work and can be released.
|
| Status | onWriteBuffer (uint32_t slotIndex, uint64_t offsetBytes, std::span< const uint8_t > data) override |
| | Backend hook: a validated buffer write.
|
| Status | onWriteTexture (uint32_t slotIndex, std::span< const uint8_t > data, const TexelCopyBufferLayout &dataLayout, const Extent2d &writeSize) override |
| | Backend hook: a validated texture write.
|
| Status | onSubmit (uint64_t submissionSerial, uint32_t commandBufferSlotIndex, std::span< const Command > commands) override |
| | Backend hook: a validated command buffer was submitted.
|
|
| Device () |
| | Constructor for backends; assigns the process-unique device identity.
|
| 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.
|
| 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 MapSliceState | onWaitMappingSlice (uint32_t mappingSlotIndex, double sliceSeconds) |
| | Backend hook: wait up to sliceSeconds for a pending mapping and report what it found.
|
| 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.
|
Metal backend of the Donner GPU runtime.
Inherits every fail-closed validation check from donner::gpu::Device; the on* hooks receive only validated input and translate it to Metal objects. Any Metal-side failure (nil object, compile error, encoder failure) fails closed with a donner::gpu::GpuError; the backend never crashes on such failures.
Scope: host-visible buffers and textures, MSL shader modules, render pipelines with a single vertex buffer layout at slot 0 and bind group 0 only, render passes with color attachments, compute pipelines and compute passes, and texture-to-buffer readback copies. Bindings follow the deterministic argument-table mapping in donner/gpu/shader/MslBindingMap.h: buffer binding b maps to Metal buffer index 1 + b, texture and sampler bindings map directly, and stage-in vertex data occupies vertex buffer index 30.
Generated runtime-array reads use the exact declared binding sizes in a fixed length table. Metal buffer index 0 is reserved for that table, so raw MSL this backend accepts must leave index 0 free. Each immutable bind group caches the table; when the bound group changes it is uploaded to every stage the active encoder has, deliberately without consulting the layout, because the generated code's need for the table follows from the shader IR rather than from a layout's binding types or visibility. Repeated draws and dispatches reuse that binding, and each new pass binds it again. Raw MSL otherwise remains trusted caller code, and omitted interface metadata retains the shared runtime's existing semantics.
Queue writes update idle resources directly. Writes to resources an earlier submission still uses are copied into bounded host storage and uploaded at the beginning of the next ordinary submission. Repeated writes of the same resource range are coalesced. A batch adds one staging allocation and no queue submission; Metal retains the staging buffer and destinations until completion. Queued and in-flight uploads share a configurable byte budget, defaulting to kMaxBufferByteSize; at most 16,384 writes may await submission. Excess writes return LimitExceeded without changing the batch. The budget counts logical upload bytes, excluding row and alignment padding. Combined queued and in-flight packed staging also stays within the larger of this budget and kMaxBufferByteSize. Packing temporarily retains both the host payload and native staging buffer. Managed resources may have separate host and device backing, so physical RAM/VRAM usage also includes those copies and driver overhead. Destroyed destinations drop unsubmitted writes; completion returns the in-flight byte reservation.
macOS buffer blits require four-byte-aligned offsets and sizes. An unaligned update instead waits at most five seconds for that buffer's last use, returning an error on timeout; it never waits for unrelated later submissions.
Memory model: unified-memory resources use MTLStorageModeShared; other devices use MTLStorageModeManaged. Managed CPU writes publish their ranges, and every submission synchronizes its GPU-written buffers before reporting completion to host readers. Textures reach the CPU through readback buffers, so unrelated buffers and textures need no scan.
Threading: single-threaded use, matching donner::gpu::Device's thread affinity. The one exception is command-buffer completion handlers, which Metal invokes on an internal queue; they touch only atomics and a mutex-protected error string, observable through completedSerial, waitForSerial, and lastErrorForTest.
The header is pure C++ (Objective-C state lives behind a pimpl) so it is includable from C++ tests; the implementation is Objective-C++.