tiny.gpu.BackendHandle
Defined in contract.
API (36)
Actions
Public operations.
acquireSurfaceFrameallocateBufferallocateTexturebackendKindcreateArtifactcreateEventcreateRenderArtifactcreateRenderBindingscreateStreamcreateSurfacedeinitdestroyObject: A caller uses this to release a buffer, queue, event or loaded code that this backend handle created.destroySurfacedestroyTextureelapsedEventNsfillBufferimportBuffer: A caller uses this to hand its own memory to a backend as a buffer without copying it.launchloadArtifactloadRenderArtifactpresentSurfaceFramequeryCapabilitiesqueryEventreadBufferreadTexturerecordEventrecordRenderBundlerendersubmitRenderBundlesynchronizewriteBufferwriteSurfaceFramewriteTexture
Fields and members
Public fields and members.
Source
Source: lib/gpu/src/contract.zig:1944
zig
pub const BackendHandle = struct { ptr: *anyopaque, vtable: *const BackendVTable, kind: ?BackendKind = null, pub fn backendKind(self: BackendHandle) ?BackendKind { return self.kind; } pub fn queryCapabilities(self: BackendHandle) BackendError!BackendCapabilities { return self.vtable.query_capabilities(self.ptr); } pub fn createArtifact(self: BackendHandle, request: CompileRequest) BackendError!KernelArtifact { const caps = try self.queryCapabilities(); try caps.validateCompileRequest(request); const create = self.vtable.create_artifact orelse return error.UnsupportedOperation; var artifact = try create(self.ptr, request); artifact.interface = .{ .features = request.required_features, .subgroup = request.required_subgroup, .push_constants = request.push_constants, }; return artifact; } pub fn loadArtifact(self: BackendHandle, artifact: *const KernelArtifact) BackendError!LoadedArtifact { try self.expectArtifactBackend(artifact); if (!artifact.interface.push_constants.valid()) return error.InvalidArtifact; const caps = try self.queryCapabilities(); if (!caps.supportsFeatures(artifact.interface.features)) return error.CapabilityMismatch; if (!caps.supportsSubgroup(artifact.interface.subgroup)) return error.CapabilityMismatch; const load = self.vtable.load_artifact orelse return error.UnsupportedOperation; return load(self.ptr, artifact); } pub fn createRenderArtifact(self: BackendHandle, desc: RenderPipelineDesc) BackendError!RenderArtifact { const caps = try self.queryCapabilities(); try caps.validateRenderPipelineDesc(desc); const create = self.vtable.create_render_artifact orelse return error.UnsupportedOperation; var artifact = try create(self.ptr, desc); errdefer artifact.deinit(); try self.expectRenderArtifactBackend(&artifact); if (artifact.format != desc.format) return error.InvalidRenderArtifact; if (artifact.target_format != desc.target_format) return error.InvalidRenderArtifact; if (artifact.blend_mode != desc.blend_mode) return error.InvalidRenderArtifact; if (artifact.topology != desc.topology) return error.InvalidRenderArtifact; return artifact; } pub fn loadRenderArtifact(self: BackendHandle, artifact: *const RenderArtifact) BackendError!LoadedRenderArtifact { try self.expectRenderArtifactBackend(artifact); if (artifact.push_extent > artifact.push_constant_bytes) return error.PushConstantRangeExceeded; const load = self.vtable.load_render_artifact orelse return error.UnsupportedOperation; const loaded = try load(self.ptr, artifact); try self.expectLoadedRenderArtifactBackend(loaded); const expected = LoadedRenderArtifact.describing(artifact, loaded.id); if (!std.meta.eql(loaded, expected)) return error.InvalidRenderArtifact; return loaded; } pub fn createRenderBindings(self: BackendHandle, request: RenderBindingsRequest) BackendError!RenderBindings { try self.expectRenderArtifactBackend(request.artifact); try self.expectLoadedRenderArtifactBackend(request.pipeline); for (request.resources) |resource| switch (resource) { .uniform_buffer, .storage_buffer => |buffer| try self.expectBufferBackend(buffer), .sampled_texture => |sampled| try self.expectTextureBackend(sampled.texture), .storage_texture => |texture| try self.expectTextureBackend(texture), }; const caps = try self.queryCapabilities(); try caps.validateRenderBindings(request); const create = self.vtable.create_render_bindings orelse return error.UnsupportedOperation; const bindings = try create(self.ptr, request); if (self.kind) |kind| { if (bindings.backend != kind) return error.CapabilityMismatch; } if (bindings.pipeline != request.pipeline.id) return error.InvalidRenderArtifact; return bindings; } pub fn allocateBuffer(self: BackendHandle, request: BufferAllocation) BackendError!BufferHandle { const caps = try self.queryCapabilities(); try caps.validateBufferAllocation(request); const allocate = self.vtable.allocate_buffer orelse return error.UnsupportedOperation; const handle = try allocate(self.ptr, request); try self.expectBufferBackend(handle); if (handle.byte_size < request.byte_size) return error.InvalidBuffer; return handle; } /// A caller uses this to hand its own memory to a backend as a buffer without copying it. The /// call binds the caller's bytes and returns a buffer whose ownership is `borrowed_external` /// and whose size equals the length of the caller's bytes. The call first checks the size, /// element type and alignment against the backend's limits, and returns `error.InvalidBuffer` /// when the pointer lacks the requested alignment. A backend that does not offer imports /// returns `error.UnsupportedOperation`, and at present only the CPU backend offers them. pub fn importBuffer(self: BackendHandle, request: BufferImport) BackendError!BufferHandle { const caps = try self.queryCapabilities(); try caps.validateBufferAllocation(.{ .byte_size = request.bytes.len, .alignment = request.alignment, .dtype = request.dtype, .element_count = request.element_count, }); std.debug.assert(std.math.isPowerOfTwo(request.alignment)); if (!std.mem.isAligned(@intFromPtr(request.bytes.ptr), request.alignment)) { return error.InvalidBuffer; } const import_fn = self.vtable.import_buffer orelse return error.UnsupportedOperation; const handle = try import_fn(self.ptr, request); try self.expectBufferBackend(handle); if (handle.ownership != .borrowed_external) return error.InvalidBuffer; if (handle.byte_size != request.bytes.len) return error.InvalidBuffer; return handle; } pub fn allocateTexture(self: BackendHandle, request: TextureAllocation) BackendError!TextureHandle { const caps = try self.queryCapabilities(); try caps.validateTextureAllocation(request); const allocate = self.vtable.allocate_texture orelse return error.UnsupportedOperation; const handle = try allocate(self.ptr, request); try self.expectTextureBackend(handle); if (!sameTextureExtent(handle.extent, request.extent)) return error.InvalidTexture; if (handle.format != request.format) return error.InvalidTexture; if (!handle.usage.containsAll(request.usage)) return error.InvalidTexture; if (handle.sample_count != request.sample_count) return error.InvalidTexture; return handle; } pub fn createSurface(self: BackendHandle, request: SurfaceCreationRequest) BackendError!SurfaceHandle { const caps = try self.queryCapabilities(); try caps.validateSurfaceCreation(request); const create = self.vtable.create_surface orelse return error.UnsupportedOperation; const handle = try create(self.ptr, request); try self.expectSurfaceBackend(handle); if (handle.platform != request.platform.kind()) return error.InvalidSurface; if (!caps.surfaces.supportsExtent(handle.extent)) return error.InvalidSurface; if (handle.format != request.format) return error.InvalidSurface; if (handle.color_space != request.color_space) return error.InvalidSurface; if (handle.present_mode != request.present_mode) return error.InvalidSurface; return handle; } pub fn destroySurface(self: BackendHandle, surface: SurfaceHandle) BackendError!void { try self.expectSurfaceBackend(surface); const destroy = self.vtable.destroy_surface orelse return error.UnsupportedOperation; return destroy(self.ptr, surface); } pub fn destroyTexture(self: BackendHandle, texture: TextureHandle) BackendError!void { try self.expectTextureBackend(texture); const destroy = self.vtable.destroy_texture orelse return error.UnsupportedOperation; return destroy(self.ptr, texture); } pub fn acquireSurfaceFrame(self: BackendHandle, request: SurfaceFrameAcquireRequest) BackendError!SurfaceFrame { try self.expectSurfaceBackend(request.surface); const acquire = self.vtable.acquire_surface_frame orelse return error.UnsupportedOperation; const frame = try acquire(self.ptr, request); try self.expectSurfaceFrameBackend(frame); try expectFrameMatchesSurface(frame, request.surface); return frame; } pub fn presentSurfaceFrame(self: BackendHandle, request: PresentRequest) BackendError!void { try self.expectSurfaceBackend(request.surface); try self.expectSurfaceFrameBackend(request.frame); try expectFrameMatchesSurface(request.frame, request.surface); for (request.wait_events) |event| try self.expectEventBackend(event); if (request.signal_event) |event| try self.expectEventBackend(event); const present = self.vtable.present_surface_frame orelse return error.UnsupportedOperation; return present(self.ptr, request); } pub fn writeSurfaceFrame(self: BackendHandle, request: SurfaceFrameWriteRequest) BackendError!void { try self.expectSurfaceBackend(request.surface); try self.expectSurfaceFrameBackend(request.frame); try expectFrameMatchesSurface(request.frame, request.surface); try expectSurfaceFrameWriteRequest(request); for (request.operations) |op| switch (op) { .clear => {}, .copy_buffer => |buffer| try self.expectBufferBackend(buffer), }; for (request.wait_events) |event| try self.expectEventBackend(event); if (request.signal_event) |event| try self.expectEventBackend(event); const write = self.vtable.write_surface_frame orelse return error.UnsupportedOperation; return write(self.ptr, request); } pub fn createStream(self: BackendHandle, request: StreamAllocation) BackendError!StreamHandle { const caps = try self.queryCapabilities(); try caps.validateRuntimeRequirements(.{ .streams = true }); const create = self.vtable.create_stream orelse return error.UnsupportedOperation; return create(self.ptr, request); } pub fn createEvent(self: BackendHandle, request: EventAllocation) BackendError!EventHandle { const caps = try self.queryCapabilities(); try caps.validateRuntimeRequirements(.{ .events = true }); const create = self.vtable.create_event orelse return error.UnsupportedOperation; return create(self.ptr, request); } pub fn writeBuffer(self: BackendHandle, request: BufferWriteRequest) BackendError!void { try self.expectBufferBackend(request.handle); const write = self.vtable.write_buffer orelse return error.UnsupportedOperation; return write(self.ptr, request); } pub fn fillBuffer(self: BackendHandle, request: BufferFillRequest) BackendError!void { try self.expectBufferBackend(request.handle); const fill = self.vtable.fill_buffer orelse return error.UnsupportedOperation; return fill(self.ptr, request); } pub fn readBuffer(self: BackendHandle, request: BufferReadRequest) BackendError!void { try self.expectBufferBackend(request.handle); if (request.bytes.len < request.handle.byte_size) return error.ReadBufferDestinationTooSmall; const read = self.vtable.read_buffer orelse return error.UnsupportedOperation; return read(self.ptr, request); } pub fn launch(self: BackendHandle, request: LaunchRequest) BackendError!void { try self.expectLaunchBackends(request); try expectLaunchArgumentCount(request); const caps = try self.queryCapabilities(); try caps.validateLaunchGeometry(request.geometry); try caps.validateLaunchRuntime(request); const launch_fn = self.vtable.launch orelse return error.UnsupportedOperation; return launch_fn(self.ptr, request); } pub fn render(self: BackendHandle, request: RenderRequest) BackendError!void { try self.expectRenderPassBackends(request.pass); try self.expectSubmitBackends(request.stream, request.wait_events, request.signal_event); const caps = try self.queryCapabilities(); try caps.validateRenderPass(request.pass); try caps.validateSubmitRuntime(request.stream, request.wait_events, request.signal_event); const render_fn = self.vtable.render orelse return error.UnsupportedOperation; return render_fn(self.ptr, request); } pub fn recordRenderBundle(self: BackendHandle, pass: RenderPass) BackendError!RenderBundle { try self.expectRenderPassBackends(pass); const caps = try self.queryCapabilities(); try caps.validateRenderPass(pass); const record = self.vtable.record_render_bundle orelse return error.UnsupportedOperation; const bundle = try record(self.ptr, pass); if (self.kind) |kind| { if (bundle.backend != kind) return error.CapabilityMismatch; } if (bundle.draw_count != pass.draws.len) return error.RenderFailed; return bundle; } pub fn submitRenderBundle(self: BackendHandle, request: RenderBundleSubmit) BackendError!void { if (self.kind) |kind| { if (request.bundle.backend != kind) return error.RenderArgumentMismatch; } try self.expectSubmitBackends(request.stream, request.wait_events, request.signal_event); const caps = try self.queryCapabilities(); try caps.validateSubmitRuntime(request.stream, request.wait_events, request.signal_event); const submit = self.vtable.submit_render_bundle orelse return error.UnsupportedOperation; return submit(self.ptr, request); } pub fn writeTexture(self: BackendHandle, request: TextureWriteRequest) BackendError!void { try self.expectTextureBackend(request.texture); try BackendCapabilities.validateTextureTransfer(request.texture, request.bytes.len, .{ .copy_dst = true }); const write = self.vtable.write_texture orelse return error.UnsupportedOperation; return write(self.ptr, request); } pub fn readTexture(self: BackendHandle, request: TextureReadRequest) BackendError!void { try self.expectTextureBackend(request.texture); try BackendCapabilities.validateTextureTransfer(request.texture, request.bytes.len, .{ .copy_src = true }); const read = self.vtable.read_texture orelse return error.UnsupportedOperation; return read(self.ptr, request); } pub fn synchronize(self: BackendHandle, request: SyncRequest) BackendError!void { if (!request.valid()) return error.UnsupportedOperation; try self.expectSyncBackends(request); const caps = try self.queryCapabilities(); try caps.validateSyncRuntime(request); const sync = self.vtable.synchronize orelse return error.UnsupportedOperation; return sync(self.ptr, request); } pub fn queryEvent(self: BackendHandle, request: EventQueryRequest) BackendError!bool { try self.expectEventBackend(request.event); const caps = try self.queryCapabilities(); try caps.validateRuntimeRequirements(.{ .events = true }); const query = self.vtable.query_event orelse return error.UnsupportedOperation; return query(self.ptr, request); } pub fn recordEvent(self: BackendHandle, request: EventRecordRequest) BackendError!void { try self.expectStreamBackend(request.stream); try self.expectEventBackend(request.event); const caps = try self.queryCapabilities(); try caps.validateRuntimeRequirements(.{ .streams = true, .events = true }); const record = self.vtable.record_event orelse return error.UnsupportedOperation; return record(self.ptr, request); } pub fn elapsedEventNs(self: BackendHandle, request: EventElapsedRequest) BackendError!u64 { try self.expectEventBackend(request.start); try self.expectEventBackend(request.end); const caps = try self.queryCapabilities(); try caps.validateRuntimeRequirements(.{ .events = true }); const elapsed = self.vtable.elapsed_event_ns orelse return error.UnsupportedOperation; return elapsed(self.ptr, request); } /// A caller uses this to release a buffer, queue, event or loaded code that this backend handle /// created. The call releases one object this handle created. Before the call, the caller makes /// sure all launches, copies, queues and events still in flight have finished using the object. /// The call leaves state unchanged on a backend lacking a release function. pub fn destroyObject(self: BackendHandle, id: BackendObjectId) void { if (self.vtable.destroy_object) |destroy| destroy(self.ptr, id); } pub fn deinit(self: BackendHandle, allocator: Allocator) void { if (self.vtable.deinit) |deinit_fn| deinit_fn(self.ptr, allocator); } fn expectArtifactBackend(self: BackendHandle, artifact: *const KernelArtifact) BackendError!void { const kind = self.kind orelse return; if (artifact.backend != kind) return error.CapabilityMismatch; } fn expectLoadedArtifactBackend(self: BackendHandle, loaded: LoadedArtifact) BackendError!void { const kind = self.kind orelse return; if (loaded.backend != kind) return error.InvalidArtifact; } fn expectRenderArtifactBackend(self: BackendHandle, artifact: *const RenderArtifact) BackendError!void { const kind = self.kind orelse return; if (artifact.backend != kind) return error.CapabilityMismatch; } fn expectLoadedRenderArtifactBackend(self: BackendHandle, loaded: LoadedRenderArtifact) BackendError!void { const kind = self.kind orelse return; if (loaded.backend != kind) return error.InvalidRenderArtifact; } fn expectBufferBackend(self: BackendHandle, handle: BufferHandle) BackendError!void { const kind = self.kind orelse return; if (handle.backend != kind) return error.InvalidBuffer; } fn expectSurfaceBackend(self: BackendHandle, handle: SurfaceHandle) BackendError!void { const kind = self.kind orelse return; if (handle.backend != kind) return error.InvalidSurface; } fn expectTextureBackend(self: BackendHandle, handle: TextureHandle) BackendError!void { const kind = self.kind orelse return; if (handle.backend != kind) return error.InvalidTexture; } fn expectTextureViewBackend(self: BackendHandle, view: TextureView) BackendError!void { try self.expectTextureBackend(view.texture); } fn expectSurfaceFrameBackend(self: BackendHandle, frame: SurfaceFrame) BackendError!void { const kind = self.kind orelse return; if (frame.backend != kind) return error.InvalidSurfaceFrame; try self.expectSurfaceBackend(frame.surface); try self.expectTextureBackend(frame.texture); try self.expectTextureViewBackend(frame.view); } fn expectStreamBackend(self: BackendHandle, handle: StreamHandle) BackendError!void { const kind = self.kind orelse return; if (handle.backend != kind) return error.InvalidStream; } fn expectEventBackend(self: BackendHandle, handle: EventHandle) BackendError!void { const kind = self.kind orelse return; if (handle.backend != kind) return error.InvalidEvent; } fn expectLaunchBackends(self: BackendHandle, request: LaunchRequest) BackendError!void { try self.expectArtifactBackend(request.artifact); if (request.loaded_artifact) |loaded| { try self.expectLoadedArtifactBackend(loaded); if (loaded.backend != request.artifact.backend or loaded.format != request.artifact.format) { return error.InvalidArtifact; } } for (request.buffers) |binding| { try self.expectBufferBackend(binding.handle); } if (request.stream) |stream| try self.expectStreamBackend(stream); for (request.wait_events) |event| try self.expectEventBackend(event); if (request.signal_event) |event| try self.expectEventBackend(event); } fn expectRenderPassBackends(self: BackendHandle, pass: RenderPass) BackendError!void { try self.expectTextureViewBackend(pass.color.view); if (pass.depth) |depth| try self.expectTextureViewBackend(depth.view); for (pass.draws) |draw| { try self.expectLoadedRenderArtifactBackend(draw.pipeline); if (draw.bindings) |bindings| { if (self.kind) |kind| { if (bindings.backend != kind) return error.RenderArgumentMismatch; } } for (draw.vertex_buffers) |range| try self.expectBufferBackend(range.buffer); if (draw.index_buffer) |range| try self.expectBufferBackend(range.buffer); } } fn expectSubmitBackends( self: BackendHandle, stream: ?StreamHandle, wait_events: []const EventHandle, signal_event: ?EventHandle, ) BackendError!void { if (stream) |handle| try self.expectStreamBackend(handle); for (wait_events) |event| try self.expectEventBackend(event); if (signal_event) |event| try self.expectEventBackend(event); } fn expectLaunchArgumentCount(request: LaunchRequest) BackendError!void { const actual = request.buffers.len + request.scalar_arguments.len; const expected: usize = @intCast(request.artifact.argument_count); if (actual != expected) return error.LaunchArgumentMismatch; } fn expectSyncBackends(self: BackendHandle, request: SyncRequest) BackendError!void { switch (request.scope) { .default_stream, .device => {}, .stream => if (request.stream) |stream| try self.expectStreamBackend(stream), .event => if (request.event) |event| try self.expectEventBackend(event), } }};Source: lib/gpu/src/root.zig:162
zig
pub const BackendHandle = contract.BackendHandle;Complete caller list for BackendHandle.queryCapabilities
18 direct callers.
tiny.gpu.BackendHandle.allocateBuffer[method] atlib/gpu/src/contract.zig:2026tiny.gpu.BackendHandle.allocateTexture[method] atlib/gpu/src/contract.zig:2062tiny.gpu.BackendHandle.createArtifact[method] atlib/gpu/src/contract.zig:1957tiny.gpu.BackendHandle.createEvent[method] atlib/gpu/src/contract.zig:2142tiny.gpu.BackendHandle.createRenderArtifact[method] atlib/gpu/src/contract.zig:1981tiny.gpu.BackendHandle.createRenderBindings[method] atlib/gpu/src/contract.zig:2007tiny.gpu.BackendHandle.createStream[method] atlib/gpu/src/contract.zig:2135tiny.gpu.BackendHandle.createSurface[method] atlib/gpu/src/contract.zig:2075tiny.gpu.BackendHandle.elapsedEventNs[method] atlib/gpu/src/contract.zig:2254tiny.gpu.BackendHandle.importBuffer[method] atlib/gpu/src/contract.zig:2042tiny.gpu.BackendHandle.launch[method] atlib/gpu/src/contract.zig:2168tiny.gpu.BackendHandle.loadArtifact[method] atlib/gpu/src/contract.zig:1971tiny.gpu.BackendHandle.queryEvent[method] atlib/gpu/src/contract.zig:2237tiny.gpu.BackendHandle.recordEvent[method] atlib/gpu/src/contract.zig:2245tiny.gpu.BackendHandle.recordRenderBundle[method] atlib/gpu/src/contract.zig:2190tiny.gpu.BackendHandle.render[method] atlib/gpu/src/contract.zig:2179tiny.gpu.BackendHandle.submitRenderBundle[method] atlib/gpu/src/contract.zig:2203tiny.gpu.BackendHandle.synchronize[method] atlib/gpu/src/contract.zig:2228
Audit
| Definitions | 34 |
|---|---|
| Public names | 68 |
| Members | 3 |
| Version | 26.7.0 |
| Revision | daab053ee433 |