lib/gpu/src/host.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

  1 const std = @import("std");
  2 const choir_abi = @import("choir_abi");
  3 
  4 const backend = @import("root.zig");
  5 
  6 pub const Binding = extern struct {
  7     handle_id: u64,
  8     access: u8,
  9     ownership: u8,
 10     reserved: [6]u8 = @splat(0),
 11     byte_size: u64,
 12 };
 13 
 14 pub const Scalar = extern struct {
 15     tag: u8,
 16     reserved: [7]u8 = @splat(0),
 17     bits: u64,
 18 };
 19 
 20 pub const ScalarTag = enum(u8) {
 21     i32 = 0,
 22     u32 = 1,
 23     i64 = 2,
 24     u64 = 3,
 25     f32 = 4,
 26     f64 = 5,
 27 };
 28 
 29 pub const Status = enum(i32) {
 30     ok = 0,
 31     invalid_artifact = 1,
 32     invalid_buffer = 2,
 33     launch_failed = 3,
 34     out_of_memory = 4,
 35     runtime_unavailable = 5,
 36 };
 37 
 38 pub fn binding(source: backend.BufferBinding) backend.BackendError!Binding {
 39     const byte_size = std.math.cast(u64, source.byte_size) orelse return error.InvalidBuffer;
 40     return .{
 41         .handle_id = source.handle.id,
 42         .access = @backingInt(source.access),
 43         .ownership = @backingInt(source.ownership),
 44         .byte_size = byte_size,
 45     };
 46 }
 47 
 48 pub fn scalar(argument: choir_abi.ScalarArgument) Scalar {
 49     return switch (argument) {
 50         .i32 => |value| .{ .tag = @backingInt(ScalarTag.i32), .bits = @as(u32, @bitCast(value)) },
 51         .u32 => |value| .{ .tag = @backingInt(ScalarTag.u32), .bits = value },
 52         .i64 => |value| .{ .tag = @backingInt(ScalarTag.i64), .bits = @as(u64, @bitCast(value)) },
 53         .u64 => |value| .{ .tag = @backingInt(ScalarTag.u64), .bits = value },
 54         .f32 => |value| .{ .tag = @backingInt(ScalarTag.f32), .bits = @as(u32, @bitCast(value)) },
 55         .f64 => |value| .{ .tag = @backingInt(ScalarTag.f64), .bits = @as(u64, @bitCast(value)) },
 56     };
 57 }
 58 
 59 pub fn status(code: i32) backend.BackendError!void {
 60     return switch (code) {
 61         @backingInt(Status.ok) => {},
 62         @backingInt(Status.invalid_artifact) => error.InvalidArtifact,
 63         @backingInt(Status.invalid_buffer) => error.InvalidBuffer,
 64         @backingInt(Status.launch_failed) => error.LaunchFailed,
 65         @backingInt(Status.out_of_memory) => error.OutOfMemory,
 66         @backingInt(Status.runtime_unavailable) => error.RuntimeUnavailable,
 67         else => error.RuntimeUnavailable,
 68     };
 69 }
 70 
 71 pub fn pointer(slice: anytype) usize {
 72     return if (slice.len == 0) 0 else @intFromPtr(slice.ptr);
 73 }
 74 
 75 test "host binding narrows buffer bindings to the wire layout" {
 76     const wire = try binding(.{
 77         .handle = .{ .id = 7, .backend = .wasm, .byte_size = 64, .ownership = .backend },
 78         .access = .read_write,
 79         .ownership = .backend,
 80         .byte_size = 64,
 81     });
 82     try std.testing.expectEqual(@as(u64, 7), wire.handle_id);
 83     try std.testing.expectEqual(@as(u64, 64), wire.byte_size);
 84     try std.testing.expectEqual(@backingInt(backend.BufferAccess.read_write), wire.access);
 85     try std.testing.expectEqual(@as(usize, 24), @sizeOf(Binding));
 86 }
 87 
 88 test "host scalar preserves bit patterns per tag" {
 89     const float_scalar = scalar(.{ .f32 = -1.5 });
 90     try std.testing.expectEqual(@backingInt(ScalarTag.f32), float_scalar.tag);
 91     try std.testing.expectEqual(@as(u64, @as(u32, @bitCast(@as(f32, -1.5)))), float_scalar.bits);
 92     try std.testing.expectEqual(@as(usize, 16), @sizeOf(Scalar));
 93 }
 94 
 95 test "host status maps wire codes onto backend errors" {
 96     try status(0);
 97     try std.testing.expectError(error.InvalidArtifact, status(1));
 98     try std.testing.expectError(error.InvalidBuffer, status(2));
 99     try std.testing.expectError(error.LaunchFailed, status(3));
100     try std.testing.expectError(error.OutOfMemory, status(4));
101     try std.testing.expectError(error.RuntimeUnavailable, status(5));
102     try std.testing.expectError(error.RuntimeUnavailable, status(99));
103 }