From 9e72a6d2bc96cfd2f7c7e2f017fb06f9c909d8e6 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Sat, 14 Mar 2026 03:59:11 +0100 Subject: [PATCH] small refactor of values --- src/GLSL_std_450/opcodes.zig | 5 +- src/Module.zig | 3 +- src/Result.zig | 441 +--------------------------------- src/Value.zig | 448 +++++++++++++++++++++++++++++++++++ src/lib.zig | 12 + src/opcodes.zig | 81 +++++-- 6 files changed, 532 insertions(+), 458 deletions(-) create mode 100644 src/Value.zig diff --git a/src/GLSL_std_450/opcodes.zig b/src/GLSL_std_450/opcodes.zig index 4e597e9..4c22a0f 100644 --- a/src/GLSL_std_450/opcodes.zig +++ b/src/GLSL_std_450/opcodes.zig @@ -8,6 +8,7 @@ const Module = @import("../Module.zig"); const Runtime = @import("../Runtime.zig"); const Result = @import("../Result.zig"); const WordIterator = @import("../WordIterator.zig"); +const Value = @import("../Value.zig").Value; const RuntimeError = Runtime.RuntimeError; const ValueType = opc.ValueType; @@ -123,7 +124,7 @@ fn MathEngine(comptime T: ValueType, comptime Op: MathOp) type { }; } - fn applyScalar(bit_count: SpvWord, d: *Result.Value, s: *const Result.Value) RuntimeError!void { + fn applyScalar(bit_count: SpvWord, d: *Value, s: *const Value) RuntimeError!void { switch (bit_count) { inline 8, 16, 32, 64 => |bits| { if (bits == 8 and T == .Float) return RuntimeError.InvalidSpirV; @@ -177,7 +178,7 @@ fn MathEngine(comptime T: ValueType, comptime Op: MathOp) type { }; } - fn applyScalar(bit_count: SpvWord, d: *Result.Value, l: *const Result.Value, r: *const Result.Value) RuntimeError!void { + fn applyScalar(bit_count: SpvWord, d: *Value, l: *const Value, r: *const Value) RuntimeError!void { switch (bit_count) { inline 8, 16, 32, 64 => |bits| { if (bits == 8 and T == .Float) return RuntimeError.InvalidSpirV; diff --git a/src/Module.zig b/src/Module.zig index c0d26fd..eb00675 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -13,10 +13,9 @@ const SpvBinding = spv.SpvBinding; const Result = @import("Result.zig"); const Runtime = @import("Runtime.zig"); +const Value = @import("Value.zig").Value; const WordIterator = @import("WordIterator.zig"); -const Value = Result.Value; - const Self = @This(); pub const ModuleOptions = struct { diff --git a/src/Result.zig b/src/Result.zig index 0617256..faea1ef 100644 --- a/src/Result.zig +++ b/src/Result.zig @@ -1,6 +1,8 @@ const std = @import("std"); const spv = @import("spv.zig"); const op = @import("opcodes.zig"); +const lib = @import("lib.zig"); +const Value = @import("Value.zig").Value; const Runtime = @import("Runtime.zig"); const RuntimeError = Runtime.RuntimeError; @@ -10,17 +12,17 @@ const SpvByte = spv.SpvByte; const SpvWord = spv.SpvWord; const SpvBool = spv.SpvBool; -pub const Vec4f32 = @Vector(4, f32); -pub const Vec3f32 = @Vector(3, f32); -pub const Vec2f32 = @Vector(2, f32); +const Vec4f32 = lib.Vec4f32; +const Vec3f32 = lib.Vec3f32; +const Vec2f32 = lib.Vec2f32; -pub const Vec4i32 = @Vector(4, i32); -pub const Vec3i32 = @Vector(3, i32); -pub const Vec2i32 = @Vector(2, i32); +const Vec4i32 = lib.Vec4i32; +const Vec3i32 = lib.Vec3i32; +const Vec2i32 = lib.Vec2i32; -pub const Vec4u32 = @Vector(4, u32); -pub const Vec3u32 = @Vector(3, u32); -pub const Vec2u32 = @Vector(2, u32); +const Vec4u32 = lib.Vec4u32; +const Vec3u32 = lib.Vec3u32; +const Vec2u32 = lib.Vec2u32; pub const Variant = enum { String, @@ -77,427 +79,6 @@ const Decoration = struct { index: SpvWord, }; -pub const Value = union(Type) { - Void: struct {}, - Bool: bool, - Int: struct { - bit_count: usize, - value: extern union { - sint8: i8, - sint16: i16, - sint32: i32, - sint64: i64, - uint8: u8, - uint16: u16, - uint32: u32, - uint64: u64, - }, - }, - Float: struct { - bit_count: usize, - value: extern union { - float16: f16, - float32: f32, - float64: f64, - }, - }, - Vector: []Value, - Vector4f32: Vec4f32, - Vector3f32: Vec3f32, - Vector2f32: Vec2f32, - Vector4i32: Vec4i32, - Vector3i32: Vec3i32, - Vector2i32: Vec2i32, - Vector4u32: Vec4u32, - Vector3u32: Vec3u32, - Vector2u32: Vec2u32, - Matrix: []Value, - Array: []Value, - RuntimeArray: struct { - type_word: SpvWord, - data: []u8, - }, - Structure: []Value, - Function: noreturn, - Image: struct {}, - Sampler: struct {}, - SampledImage: struct {}, - Pointer: struct { - ptr: union(enum) { - common: *Value, - f32_ptr: *f32, - i32_ptr: *i32, //< For vector specializations - u32_ptr: *u32, - }, - runtime_array_window: ?[]u8 = null, - }, - - pub inline fn getCompositeDataOrNull(self: *const Value) ?[]Value { - return switch (self.*) { - .Vector, .Matrix, .Array, .Structure => |v| v, - else => null, - }; - } - - pub fn init(allocator: std.mem.Allocator, results: []const Self, target: SpvWord) RuntimeError!Value { - const resolved = results[target].resolveType(results); - const member_count = resolved.getMemberCounts(); - - return switch (resolved.variant.?) { - .Type => |t| switch (t) { - .Bool => .{ .Bool = false }, - .Int => |i| .{ .Int = .{ - .bit_count = i.bit_length, - .value = .{ .uint64 = 0 }, - } }, - .Float => |f| .{ .Float = .{ - .bit_count = f.bit_length, - .value = .{ .float64 = 0 }, - } }, - .Vector => |v| blk: { - var self: Value = .{ .Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory }; - errdefer self.deinit(allocator); - - for (self.Vector) |*value| { - value.* = try Value.init(allocator, results, v.components_type_word); - } - break :blk self; - }, - .Vector4f32 => .{ .Vector4f32 = Vec4f32{ 0.0, 0.0, 0.0, 0.0 } }, - .Vector3f32 => .{ .Vector3f32 = Vec3f32{ 0.0, 0.0, 0.0 } }, - .Vector2f32 => .{ .Vector2f32 = Vec2f32{ 0.0, 0.0 } }, - .Vector4i32 => .{ .Vector4i32 = Vec4i32{ 0, 0, 0, 0 } }, - .Vector3i32 => .{ .Vector3i32 = Vec3i32{ 0, 0, 0 } }, - .Vector2i32 => .{ .Vector2i32 = Vec2i32{ 0, 0 } }, - .Vector4u32 => .{ .Vector4u32 = Vec4u32{ 0, 0, 0, 0 } }, - .Vector3u32 => .{ .Vector3u32 = Vec3u32{ 0, 0, 0 } }, - .Vector2u32 => .{ .Vector2u32 = Vec2u32{ 0, 0 } }, - .Matrix => |m| blk: { - var self: Value = .{ .Matrix = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory }; - errdefer self.deinit(allocator); - - for (self.Matrix) |*value| { - value.* = try Value.init(allocator, results, m.column_type_word); - } - break :blk self; - }, - .Array => |a| blk: { - var self: Value = .{ .Array = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory }; - errdefer self.deinit(allocator); - - for (self.Array) |*value| { - value.* = try Value.init(allocator, results, a.components_type_word); - } - break :blk self; - }, - .Structure => |s| blk: { - var self: Value = .{ .Structure = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory }; - errdefer self.deinit(allocator); - - for (self.Structure, s.members_type_word) |*value, member_type_word| { - value.* = try Value.init(allocator, results, member_type_word); - } - break :blk self; - }, - .RuntimeArray => |a| .{ - .RuntimeArray = .{ - .type_word = a.components_type_word, - .data = &.{}, - }, - }, - else => unreachable, - }, - else => unreachable, - }; - } - - /// Performs a deep copy - pub fn dupe(self: *const Value, allocator: std.mem.Allocator) RuntimeError!Value { - return switch (self.*) { - .Vector => |v| .{ - .Vector = blk: { - const values = allocator.dupe(Value, v) catch return RuntimeError.OutOfMemory; - for (values, v) |*new_value, value| new_value.* = try value.dupe(allocator); - break :blk values; - }, - }, - .Matrix => |m| .{ - .Matrix = blk: { - const values = allocator.dupe(Value, m) catch return RuntimeError.OutOfMemory; - for (values, m) |*new_value, value| new_value.* = try value.dupe(allocator); - break :blk values; - }, - }, - .Array => |a| .{ - .Array = blk: { - const values = allocator.dupe(Value, a) catch return RuntimeError.OutOfMemory; - for (values, a) |*new_value, value| new_value.* = try value.dupe(allocator); - break :blk values; - }, - }, - .Structure => |s| .{ - .Structure = blk: { - const values = allocator.dupe(Value, s) catch return RuntimeError.OutOfMemory; - for (values, s) |*new_value, value| new_value.* = try value.dupe(allocator); - break :blk values; - }, - }, - else => self.*, - }; - } - - pub fn read(self: *const Value, output: []u8) RuntimeError!usize { - switch (self.*) { - .Bool => |b| { - output[0] = if (b == true) 1 else 0; - return 1; - }, - .Int => |i| { - switch (i.bit_count) { - 8 => output[0] = @bitCast(i.value.uint8), - 16 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint16)), - 32 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint32)), - 64 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint64)), - else => return RuntimeError.InvalidValueType, - } - return @divExact(i.bit_count, 8); - }, - .Float => |f| { - switch (f.bit_count) { - 16 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float16)), - 32 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float32)), - 64 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float64)), - else => return RuntimeError.InvalidValueType, - } - return @divExact(f.bit_count, 8); - }, - .Vector4f32 => |vec| { - inline for (0..4) |i| { - std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); - } - return 4 * 4; - }, - .Vector3f32 => |vec| { - inline for (0..3) |i| { - std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); - } - return 3 * 4; - }, - .Vector2f32 => |vec| { - inline for (0..2) |i| { - std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); - } - return 2 * 4; - }, - .Vector4i32 => |vec| { - inline for (0..4) |i| { - std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); - } - return 4 * 4; - }, - .Vector3i32 => |vec| { - inline for (0..3) |i| { - std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); - } - return 3 * 4; - }, - .Vector2i32 => |vec| { - inline for (0..2) |i| { - std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); - } - return 2 * 4; - }, - .Vector4u32 => |vec| { - inline for (0..4) |i| { - std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); - } - return 4 * 4; - }, - .Vector3u32 => |vec| { - inline for (0..3) |i| { - std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); - } - return 3 * 4; - }, - .Vector2u32 => |vec| { - inline for (0..2) |i| { - std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); - } - return 2 * 4; - }, - .Vector, - .Matrix, - .Array, - .Structure, - => |values| { - var offset: usize = 0; - for (values) |v| { - offset += try v.read(output[offset..]); - } - return offset; - }, - else => return RuntimeError.InvalidValueType, - } - return 0; - } - - pub fn writeConst(self: *Value, input: []const u8) RuntimeError!usize { - return self.write(@constCast(input)); - } - - pub fn write(self: *Value, input: []u8) RuntimeError!usize { - switch (self.*) { - .Bool => |*b| { - b.* = if (input[0] != 0) true else false; - return 1; - }, - .Int => |*i| { - switch (i.bit_count) { - 8 => i.value.uint8 = @bitCast(input[0]), - 16 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint16), input[0..2]), - 32 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint32), input[0..4]), - 64 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint64), input[0..8]), - else => return RuntimeError.InvalidValueType, - } - return @divExact(i.bit_count, 8); - }, - .Float => |*f| { - switch (f.bit_count) { - 16 => std.mem.copyForwards(u8, std.mem.asBytes(&f.value.float16), input[0..2]), - 32 => std.mem.copyForwards(u8, std.mem.asBytes(&f.value.float32), input[0..4]), - 64 => std.mem.copyForwards(u8, std.mem.asBytes(&f.value.float64), input[0..8]), - else => return RuntimeError.InvalidValueType, - } - return @divExact(f.bit_count, 8); - }, - .Vector4f32 => |*vec| { - inline for (0..4) |i| { - const start = i * 4; - const end = (i + 1) * 4; - if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; - std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); - } - return 4 * 4; - }, - .Vector3f32 => |*vec| { - inline for (0..3) |i| { - const start = i * 4; - const end = (i + 1) * 4; - if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; - std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); - } - return 3 * 4; - }, - .Vector2f32 => |*vec| { - inline for (0..2) |i| { - const start = i * 4; - const end = (i + 1) * 4; - if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; - std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); - } - return 2 * 4; - }, - .Vector4i32 => |*vec| { - inline for (0..4) |i| { - const start = i * 4; - const end = (i + 1) * 4; - if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; - std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); - } - return 4 * 4; - }, - .Vector3i32 => |*vec| { - inline for (0..3) |i| { - const start = i * 4; - const end = (i + 1) * 4; - if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; - std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); - } - return 3 * 4; - }, - .Vector2i32 => |*vec| { - inline for (0..2) |i| { - const start = i * 4; - const end = (i + 1) * 4; - if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; - std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); - } - return 2 * 4; - }, - .Vector4u32 => |*vec| { - inline for (0..4) |i| { - const start = i * 4; - const end = (i + 1) * 4; - if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; - std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); - } - return 4 * 4; - }, - .Vector3u32 => |*vec| { - inline for (0..3) |i| { - const start = i * 4; - const end = (i + 1) * 4; - if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; - std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); - } - return 3 * 4; - }, - .Vector2u32 => |*vec| { - inline for (0..2) |i| { - const start = i * 4; - const end = (i + 1) * 4; - if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; - std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); - } - return 2 * 4; - }, - .Vector, - .Matrix, - .Array, - .Structure, - => |*values| { - var offset: usize = 0; - for (values.*) |*v| { - offset += try v.write(input[offset..]); - } - return offset; - }, - .RuntimeArray => |*arr| arr.data = input[0..], - else => return RuntimeError.InvalidValueType, - } - return 0; - } - - pub fn flushPtr(self: *Value, allocator: std.mem.Allocator) RuntimeError!void { - switch (self.*) { - .Pointer => |*p| { - if (p.runtime_array_window) |window| { - switch (p.ptr) { - .common => |ptr| { - _ = try ptr.read(window); - ptr.deinit(allocator); - allocator.destroy(ptr); - }, - else => {}, - } - } - p.runtime_array_window = null; - }, - else => {}, - } - } - - fn deinit(self: *Value, allocator: std.mem.Allocator) void { - switch (self.*) { - .Vector, .Matrix, .Array, .Structure => |values| { - for (values) |*value| value.deinit(allocator); - allocator.free(values); - }, - else => {}, - } - } -}; - pub const TypeData = union(Type) { Void: struct {}, Bool: struct {}, diff --git a/src/Value.zig b/src/Value.zig new file mode 100644 index 0000000..a62d069 --- /dev/null +++ b/src/Value.zig @@ -0,0 +1,448 @@ +const std = @import("std"); +const lib = @import("lib.zig"); + +const Result = @import("Result.zig"); +const Runtime = @import("Runtime.zig"); +const RuntimeError = Runtime.RuntimeError; + +const SpvVoid = lib.SpvVoid; +const SpvByte = lib.SpvByte; +const SpvWord = lib.SpvWord; +const SpvBool = lib.SpvBool; + +const Vec4f32 = lib.Vec4f32; +const Vec3f32 = lib.Vec3f32; +const Vec2f32 = lib.Vec2f32; + +const Vec4i32 = lib.Vec4i32; +const Vec3i32 = lib.Vec3i32; +const Vec2i32 = lib.Vec2i32; + +const Vec4u32 = lib.Vec4u32; +const Vec3u32 = lib.Vec3u32; +const Vec2u32 = lib.Vec2u32; + +const Type = Result.Type; + +pub const Value = union(Type) { + const Self = @This(); + + Void: struct {}, + Bool: bool, + Int: struct { + bit_count: usize, + value: extern union { + sint8: i8, + sint16: i16, + sint32: i32, + sint64: i64, + uint8: u8, + uint16: u16, + uint32: u32, + uint64: u64, + }, + }, + Float: struct { + bit_count: usize, + value: extern union { + float16: f16, + float32: f32, + float64: f64, + }, + }, + Vector: []Self, + Vector4f32: Vec4f32, + Vector3f32: Vec3f32, + Vector2f32: Vec2f32, + Vector4i32: Vec4i32, + Vector3i32: Vec3i32, + Vector2i32: Vec2i32, + Vector4u32: Vec4u32, + Vector3u32: Vec3u32, + Vector2u32: Vec2u32, + Matrix: []Self, + Array: []Self, + RuntimeArray: struct { + type_word: SpvWord, + data: []u8, + }, + Structure: []Self, + Function: noreturn, + Image: struct {}, + Sampler: struct {}, + SampledImage: struct {}, + Pointer: struct { + ptr: union(enum) { + common: *Self, + f32_ptr: *f32, + i32_ptr: *i32, //< For vector specializations + u32_ptr: *u32, + }, + runtime_array_window: ?[]u8 = null, + }, + + pub inline fn getCompositeDataOrNull(self: *const Self) ?[]Self { + return switch (self.*) { + .Vector, .Matrix, .Array, .Structure => |v| v, + else => null, + }; + } + + pub fn init(allocator: std.mem.Allocator, results: []const Result, target: SpvWord) RuntimeError!Self { + const resolved = results[target].resolveType(results); + const member_count = resolved.getMemberCounts(); + + return switch (resolved.variant.?) { + .Type => |t| switch (t) { + .Bool => .{ .Bool = false }, + .Int => |i| .{ .Int = .{ + .bit_count = i.bit_length, + .value = .{ .uint64 = 0 }, + } }, + .Float => |f| .{ .Float = .{ + .bit_count = f.bit_length, + .value = .{ .float64 = 0 }, + } }, + .Vector => |v| blk: { + var self: Self = .{ .Vector = allocator.alloc(Self, member_count) catch return RuntimeError.OutOfMemory }; + errdefer self.deinit(allocator); + + for (self.Vector) |*value| { + value.* = try Self.init(allocator, results, v.components_type_word); + } + break :blk self; + }, + .Vector4f32 => .{ .Vector4f32 = Vec4f32{ 0.0, 0.0, 0.0, 0.0 } }, + .Vector3f32 => .{ .Vector3f32 = Vec3f32{ 0.0, 0.0, 0.0 } }, + .Vector2f32 => .{ .Vector2f32 = Vec2f32{ 0.0, 0.0 } }, + .Vector4i32 => .{ .Vector4i32 = Vec4i32{ 0, 0, 0, 0 } }, + .Vector3i32 => .{ .Vector3i32 = Vec3i32{ 0, 0, 0 } }, + .Vector2i32 => .{ .Vector2i32 = Vec2i32{ 0, 0 } }, + .Vector4u32 => .{ .Vector4u32 = Vec4u32{ 0, 0, 0, 0 } }, + .Vector3u32 => .{ .Vector3u32 = Vec3u32{ 0, 0, 0 } }, + .Vector2u32 => .{ .Vector2u32 = Vec2u32{ 0, 0 } }, + .Matrix => |m| blk: { + var self: Self = .{ .Matrix = allocator.alloc(Self, member_count) catch return RuntimeError.OutOfMemory }; + errdefer self.deinit(allocator); + + for (self.Matrix) |*value| { + value.* = try Self.init(allocator, results, m.column_type_word); + } + break :blk self; + }, + .Array => |a| blk: { + var self: Self = .{ .Array = allocator.alloc(Self, member_count) catch return RuntimeError.OutOfMemory }; + errdefer self.deinit(allocator); + + for (self.Array) |*value| { + value.* = try Self.init(allocator, results, a.components_type_word); + } + break :blk self; + }, + .Structure => |s| blk: { + var self: Self = .{ .Structure = allocator.alloc(Self, member_count) catch return RuntimeError.OutOfMemory }; + errdefer self.deinit(allocator); + + for (self.Structure, s.members_type_word) |*value, member_type_word| { + value.* = try Self.init(allocator, results, member_type_word); + } + break :blk self; + }, + .RuntimeArray => |a| .{ + .RuntimeArray = .{ + .type_word = a.components_type_word, + .data = &.{}, + }, + }, + else => unreachable, + }, + else => unreachable, + }; + } + + /// Performs a deep copy + pub fn dupe(self: *const Self, allocator: std.mem.Allocator) RuntimeError!Self { + return switch (self.*) { + .Vector => |v| .{ + .Vector = blk: { + const values = allocator.dupe(Self, v) catch return RuntimeError.OutOfMemory; + for (values, v) |*new_value, value| new_value.* = try value.dupe(allocator); + break :blk values; + }, + }, + .Matrix => |m| .{ + .Matrix = blk: { + const values = allocator.dupe(Self, m) catch return RuntimeError.OutOfMemory; + for (values, m) |*new_value, value| new_value.* = try value.dupe(allocator); + break :blk values; + }, + }, + .Array => |a| .{ + .Array = blk: { + const values = allocator.dupe(Self, a) catch return RuntimeError.OutOfMemory; + for (values, a) |*new_value, value| new_value.* = try value.dupe(allocator); + break :blk values; + }, + }, + .Structure => |s| .{ + .Structure = blk: { + const values = allocator.dupe(Self, s) catch return RuntimeError.OutOfMemory; + for (values, s) |*new_value, value| new_value.* = try value.dupe(allocator); + break :blk values; + }, + }, + else => self.*, + }; + } + + pub fn read(self: *const Self, output: []u8) RuntimeError!usize { + switch (self.*) { + .Bool => |b| { + output[0] = if (b == true) 1 else 0; + return 1; + }, + .Int => |i| { + switch (i.bit_count) { + 8 => output[0] = @bitCast(i.value.uint8), + 16 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint16)), + 32 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint32)), + 64 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&i.value.uint64)), + else => return RuntimeError.InvalidValueType, + } + return @divExact(i.bit_count, 8); + }, + .Float => |f| { + switch (f.bit_count) { + 16 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float16)), + 32 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float32)), + 64 => std.mem.copyForwards(u8, output[0..], std.mem.asBytes(&f.value.float64)), + else => return RuntimeError.InvalidValueType, + } + return @divExact(f.bit_count, 8); + }, + .Vector4f32 => |vec| { + inline for (0..4) |i| { + std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); + } + return 4 * 4; + }, + .Vector3f32 => |vec| { + inline for (0..3) |i| { + std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); + } + return 3 * 4; + }, + .Vector2f32 => |vec| { + inline for (0..2) |i| { + std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); + } + return 2 * 4; + }, + .Vector4i32 => |vec| { + inline for (0..4) |i| { + std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); + } + return 4 * 4; + }, + .Vector3i32 => |vec| { + inline for (0..3) |i| { + std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); + } + return 3 * 4; + }, + .Vector2i32 => |vec| { + inline for (0..2) |i| { + std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); + } + return 2 * 4; + }, + .Vector4u32 => |vec| { + inline for (0..4) |i| { + std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); + } + return 4 * 4; + }, + .Vector3u32 => |vec| { + inline for (0..3) |i| { + std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); + } + return 3 * 4; + }, + .Vector2u32 => |vec| { + inline for (0..2) |i| { + std.mem.copyForwards(u8, output[(i * 4)..], std.mem.asBytes(&vec[i])); + } + return 2 * 4; + }, + .Vector, + .Matrix, + .Array, + .Structure, + => |values| { + var offset: usize = 0; + for (values) |v| { + offset += try v.read(output[offset..]); + } + return offset; + }, + else => return RuntimeError.InvalidValueType, + } + return 0; + } + + pub fn writeConst(self: *Self, input: []const u8) RuntimeError!usize { + return self.write(@constCast(input)); + } + + pub fn write(self: *Self, input: []u8) RuntimeError!usize { + switch (self.*) { + .Bool => |*b| { + b.* = if (input[0] != 0) true else false; + return 1; + }, + .Int => |*i| { + switch (i.bit_count) { + 8 => i.value.uint8 = @bitCast(input[0]), + 16 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint16), input[0..2]), + 32 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint32), input[0..4]), + 64 => std.mem.copyForwards(u8, std.mem.asBytes(&i.value.uint64), input[0..8]), + else => return RuntimeError.InvalidValueType, + } + return @divExact(i.bit_count, 8); + }, + .Float => |*f| { + switch (f.bit_count) { + 16 => std.mem.copyForwards(u8, std.mem.asBytes(&f.value.float16), input[0..2]), + 32 => std.mem.copyForwards(u8, std.mem.asBytes(&f.value.float32), input[0..4]), + 64 => std.mem.copyForwards(u8, std.mem.asBytes(&f.value.float64), input[0..8]), + else => return RuntimeError.InvalidValueType, + } + return @divExact(f.bit_count, 8); + }, + .Vector4f32 => |*vec| { + inline for (0..4) |i| { + const start = i * 4; + const end = (i + 1) * 4; + if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; + std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); + } + return 4 * 4; + }, + .Vector3f32 => |*vec| { + inline for (0..3) |i| { + const start = i * 4; + const end = (i + 1) * 4; + if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; + std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); + } + return 3 * 4; + }, + .Vector2f32 => |*vec| { + inline for (0..2) |i| { + const start = i * 4; + const end = (i + 1) * 4; + if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; + std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); + } + return 2 * 4; + }, + .Vector4i32 => |*vec| { + inline for (0..4) |i| { + const start = i * 4; + const end = (i + 1) * 4; + if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; + std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); + } + return 4 * 4; + }, + .Vector3i32 => |*vec| { + inline for (0..3) |i| { + const start = i * 4; + const end = (i + 1) * 4; + if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; + std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); + } + return 3 * 4; + }, + .Vector2i32 => |*vec| { + inline for (0..2) |i| { + const start = i * 4; + const end = (i + 1) * 4; + if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; + std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); + } + return 2 * 4; + }, + .Vector4u32 => |*vec| { + inline for (0..4) |i| { + const start = i * 4; + const end = (i + 1) * 4; + if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; + std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); + } + return 4 * 4; + }, + .Vector3u32 => |*vec| { + inline for (0..3) |i| { + const start = i * 4; + const end = (i + 1) * 4; + if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; + std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); + } + return 3 * 4; + }, + .Vector2u32 => |*vec| { + inline for (0..2) |i| { + const start = i * 4; + const end = (i + 1) * 4; + if (start >= input.len or end > input.len) return RuntimeError.OutOfBounds; + std.mem.copyForwards(u8, std.mem.asBytes(&vec[i]), input[start..end]); + } + return 2 * 4; + }, + .Vector, + .Matrix, + .Array, + .Structure, + => |*values| { + var offset: usize = 0; + for (values.*) |*v| { + offset += try v.write(input[offset..]); + } + return offset; + }, + .RuntimeArray => |*arr| arr.data = input[0..], + else => return RuntimeError.InvalidValueType, + } + return 0; + } + + pub fn flushPtr(self: *Self, allocator: std.mem.Allocator) RuntimeError!void { + switch (self.*) { + .Pointer => |*p| { + if (p.runtime_array_window) |window| { + switch (p.ptr) { + .common => |ptr| { + _ = try ptr.read(window); + ptr.deinit(allocator); + allocator.destroy(ptr); + }, + else => {}, + } + } + p.runtime_array_window = null; + }, + else => {}, + } + } + + pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { + switch (self.*) { + .Vector, .Matrix, .Array, .Structure => |values| { + for (values) |*value| value.deinit(allocator); + allocator.free(values); + }, + else => {}, + } + } +}; diff --git a/src/lib.zig b/src/lib.zig index 3057d63..9657563 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -42,6 +42,18 @@ pub const SpvByte = spv.SpvByte; pub const SpvWord = spv.SpvWord; pub const SpvBool = spv.SpvBool; +pub const Vec4f32 = @Vector(4, f32); +pub const Vec3f32 = @Vector(3, f32); +pub const Vec2f32 = @Vector(2, f32); + +pub const Vec4i32 = @Vector(4, i32); +pub const Vec3i32 = @Vector(3, i32); +pub const Vec2i32 = @Vector(2, i32); + +pub const Vec4u32 = @Vector(4, u32); +pub const Vec3u32 = @Vector(3, u32); +pub const Vec2u32 = @Vector(2, u32); + pub const GLSL_std_450 = @import("GLSL_std_450/opcodes.zig"); /// Maximum number of input locations per module diff --git a/src/opcodes.zig b/src/opcodes.zig index 6b96e8c..45937b7 100644 --- a/src/opcodes.zig +++ b/src/opcodes.zig @@ -7,6 +7,7 @@ const GLSL_std_450 = @import("GLSL_std_450/opcodes.zig"); const Module = @import("Module.zig"); const Runtime = @import("Runtime.zig"); const Result = @import("Result.zig"); +const Value = @import("Value.zig").Value; const WordIterator = @import("WordIterator.zig"); const RuntimeError = Runtime.RuntimeError; @@ -359,7 +360,7 @@ fn BitOperator(comptime T: ValueType, comptime Op: BitOp) type { }; } - fn applyScalarBits(rt: *Runtime, bit_count: SpvWord, dst: *Result.Value, op1_v: *const Result.Value, op2_v: ?*const Result.Value) RuntimeError!void { + fn applyScalarBits(rt: *Runtime, bit_count: SpvWord, dst: *Value, op1_v: *const Value, op2_v: ?*const Value) RuntimeError!void { switch (bit_count) { inline 8, 16, 32, 64 => |bits| { const TT = getValuePrimitiveFieldType(T, bits); @@ -379,13 +380,13 @@ fn BitOperator(comptime T: ValueType, comptime Op: BitOp) type { } } - fn laneRhsPtr(op2_value: ?*Result.Value, index: usize) ?*const Result.Value { + fn laneRhsPtr(op2_value: ?*Value, index: usize) ?*const Value { if (comptime isUnaryOp()) return null; const v = op2_value orelse return null; return &v.Vector[index]; } - fn applyFixedVector(comptime ElemT: type, comptime N: usize, dst: *[N]ElemT, op1: *[N]ElemT, op2_value: ?*Result.Value) RuntimeError!void { + fn applyFixedVector(comptime ElemT: type, comptime N: usize, dst: *[N]ElemT, op1: *[N]ElemT, op2_value: ?*Value) RuntimeError!void { if (comptime isUnaryOp()) { inline for (0..N) |i| dst[i] = try operationUnary(ElemT, op1[i]); } else { @@ -432,7 +433,7 @@ fn BitEngine(comptime T: ValueType, comptime Op: BitOp) type { const operator = BitOperator(T, Op); - const op2_value: ?*Result.Value = if (comptime operator.isUnaryOp()) null else try rt.results[try rt.it.next()].getValue(); + const op2_value: ?*Value = if (comptime operator.isUnaryOp()) null else try rt.results[try rt.it.next()].getValue(); const lane_bits = try Result.resolveLaneBitWidth(target_type, rt); @@ -529,7 +530,7 @@ fn CondOperator(comptime T: ValueType, comptime Op: CondOp) type { }; } - fn applyLane(bit_count: SpvWord, dst_bool: *Result.Value, a_v: *const Result.Value, b_v: ?*const Result.Value) RuntimeError!void { + fn applyLane(bit_count: SpvWord, dst_bool: *Value, a_v: *const Value, b_v: ?*const Value) RuntimeError!void { switch (bit_count) { inline 8, 16, 32, 64 => |bits| { if (bits == 8 and T == .Float) return RuntimeError.InvalidSpirV; @@ -549,7 +550,7 @@ fn CondOperator(comptime T: ValueType, comptime Op: CondOp) type { } } - fn laneRhsPtr(op2_value: ?*Result.Value, index: usize) ?*const Result.Value { + fn laneRhsPtr(op2_value: ?*Value, index: usize) ?*const Value { if (comptime Op == .LogicalNot) return null; const v = op2_value orelse return null; return &v.Vector[index]; @@ -572,7 +573,7 @@ fn CondEngine(comptime T: ValueType, comptime Op: CondOp) type { const op1_type = try op1_result.getValueTypeWord(); const op1_value = try op1_result.getValue(); - const op2_value: ?*Result.Value = if (unary_condition_set.contains(Op)) null else try rt.results[try rt.it.next()].getValue(); + const op2_value: ?*Value = if (unary_condition_set.contains(Op)) null else try rt.results[try rt.it.next()].getValue(); const lane_bits = try Result.resolveLaneBitWidth((try rt.results[op1_type].getVariant()).Type, rt); @@ -606,7 +607,7 @@ fn ConversionEngine(comptime from_kind: ValueType, comptime to_kind: ValueType) const to_bits = try Result.resolveLaneBitWidth(target_type, rt); const caster = struct { - fn castLane(comptime ToT: type, from_bit_count: SpvWord, from: *Result.Value) RuntimeError!ToT { + fn castLane(comptime ToT: type, from_bit_count: SpvWord, from: *Value) RuntimeError!ToT { return switch (from_bit_count) { inline 8, 16, 32, 64 => |bits| blk: { if (bits == 8 and from_kind == .Float) return RuntimeError.InvalidSpirV; // No f8 @@ -617,7 +618,7 @@ fn ConversionEngine(comptime from_kind: ValueType, comptime to_kind: ValueType) }; } - fn applyScalar(from_bit_count: SpvWord, to_bit_count: SpvWord, dst: *Result.Value, from: *Result.Value) RuntimeError!void { + fn applyScalar(from_bit_count: SpvWord, to_bit_count: SpvWord, dst: *Value, from: *Value) RuntimeError!void { switch (to_bit_count) { inline 8, 16, 32, 64 => |bits| { if (bits == 8 and to_kind == .Float) return RuntimeError.InvalidSpirV; // No f8 @@ -743,7 +744,7 @@ fn MathEngine(comptime T: ValueType, comptime Op: MathOp) type { }; } - fn applyScalar(bit_count: SpvWord, d: *Result.Value, l: *Result.Value, r: *Result.Value) RuntimeError!void { + fn applyScalar(bit_count: SpvWord, d: *Value, l: *Value, r: *Value) RuntimeError!void { switch (bit_count) { inline 8, 16, 32, 64 => |bits| { if (bits == 8 and T == .Float) return RuntimeError.InvalidSpirV; @@ -758,7 +759,7 @@ fn MathEngine(comptime T: ValueType, comptime Op: MathOp) type { } } - inline fn applyVectorTimesScalarF32(d: []Result.Value, l: []const Result.Value, r: f32) void { + inline fn applyVectorTimesScalarF32(d: []Value, l: []const Value, r: f32) void { for (d, l) |*d_v, l_v| { d_v.Float.value.float32 = l_v.Float.value.float32 * r; } @@ -776,7 +777,7 @@ fn MathEngine(comptime T: ValueType, comptime Op: MathOp) type { } } - inline fn applySIMDVectorf32(comptime N: usize, d: *@Vector(N, f32), l: *const @Vector(N, f32), r: *const Result.Value) RuntimeError!void { + inline fn applySIMDVectorf32(comptime N: usize, d: *@Vector(N, f32), l: *const @Vector(N, f32), r: *const Value) RuntimeError!void { switch (Op) { .VectorTimesScalar => applyVectorSIMDTimesScalarF32(N, d, l, r.Float.value.float32), else => { @@ -833,7 +834,7 @@ fn MathEngine(comptime T: ValueType, comptime Op: MathOp) type { }; } - fn applyScalar(bit_count: SpvWord, d: *Result.Value, v: *Result.Value) RuntimeError!void { + fn applyScalar(bit_count: SpvWord, d: *Value, v: *Value) RuntimeError!void { switch (bit_count) { inline 8, 16, 32, 64 => |bits| { if (bits == 8 and T == .Float) return RuntimeError.InvalidSpirV; @@ -938,7 +939,7 @@ fn opBitcast(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { const caster = struct { /// Asumes that values passed are primitives ints or floats - fn cast(to: *Result.Value, from: *const Result.Value) RuntimeError!void { + fn cast(to: *Value, from: *const Value) RuntimeError!void { const from_bytes: u64 = switch (from.*) { .Float => |f| @bitCast(f.value.float64), .Int => |i| i.value.uint64, @@ -961,22 +962,22 @@ fn opBitcast(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { } } -fn copyValue(dst: *Result.Value, src: *const Result.Value) void { +fn copyValue(dst: *Value, src: *const Value) void { const helpers = struct { - inline fn copySlice(dst_slice: []Result.Value, src_slice: []const Result.Value) void { + inline fn copySlice(dst_slice: []Value, src_slice: []const Value) void { for (0..@min(dst_slice.len, src_slice.len)) |i| { copyValue(&dst_slice[i], &src_slice[i]); } } - inline fn getDstSlice(v: *Result.Value) ?[]Result.Value { + inline fn getDstSlice(v: *Value) ?[]Value { return switch (v.*) { .Vector, .Matrix, .Array, .Structure => |s| s, else => null, }; } - inline fn writeF32(dst_f32_ptr: *f32, src_v: *const Result.Value) void { + inline fn writeF32(dst_f32_ptr: *f32, src_v: *const Value) void { switch (src_v.*) { .Pointer => |src_ptr| switch (src_ptr.ptr) { .f32_ptr => |src_f32_ptr| dst_f32_ptr.* = src_f32_ptr.*, @@ -988,7 +989,7 @@ fn copyValue(dst: *Result.Value, src: *const Result.Value) void { } } - inline fn writeI32(dst_i32_ptr: *i32, src_v: *const Result.Value) void { + inline fn writeI32(dst_i32_ptr: *i32, src_v: *const Value) void { switch (src_v.*) { .Pointer => |src_ptr| switch (src_ptr.ptr) { .i32_ptr => |src_i32_ptr| dst_i32_ptr.* = src_i32_ptr.*, @@ -1000,7 +1001,7 @@ fn copyValue(dst: *Result.Value, src: *const Result.Value) void { } } - inline fn writeU32(dst_u32_ptr: *u32, src_v: *const Result.Value) void { + inline fn writeU32(dst_u32_ptr: *u32, src_v: *const Value) void { switch (src_v.*) { .Pointer => |src_ptr| switch (src_ptr.ptr) { .u32_ptr => |src_u32_ptr| dst_u32_ptr.* = src_u32_ptr.*, @@ -1050,7 +1051,7 @@ fn copyValue(dst: *Result.Value, src: *const Result.Value) void { } } -pub fn getValuePrimitiveField(comptime T: ValueType, comptime BitCount: SpvWord, v: *Result.Value) RuntimeError!*getValuePrimitiveFieldType(T, BitCount) { +pub fn getValuePrimitiveField(comptime T: ValueType, comptime BitCount: SpvWord, v: *Value) RuntimeError!*getValuePrimitiveFieldType(T, BitCount) { if (std.meta.activeTag(v.*) == .Pointer) { return switch (v.Pointer.ptr) { .common => |value| getValuePrimitiveField(T, BitCount, value), @@ -1138,10 +1139,10 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime const concrete_allocator = if (is_last) allocator else arena_allocator; const type_size = (try rt.results[arr.type_word].getVariant()).Type.getSize(rt.results); - value_ptr = concrete_allocator.create(Result.Value) catch return RuntimeError.OutOfMemory; + value_ptr = concrete_allocator.create(Value) catch return RuntimeError.OutOfMemory; errdefer concrete_allocator.destroy(value_ptr); - value_ptr.* = try Result.Value.init(concrete_allocator, rt.results, arr.type_word); + value_ptr.* = try Value.init(concrete_allocator, rt.results, arr.type_word); _ = try value_ptr.writeConst(arr.data[(type_size * i.value.uint32)..]); if (is_last) @@ -1314,7 +1315,7 @@ fn opCompositeExtract(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Ru switch (composite) { .RuntimeArray => |arr| { const type_size = (try rt.results[arr.type_word].getVariant()).Type.getSize(rt.results); - composite = try Result.Value.init(arena_allocator, rt.results, arr.type_word); + composite = try Value.init(arena_allocator, rt.results, arr.type_word); _ = try composite.writeConst(arr.data[(type_size * member_id)..]); }, .Vector4f32 => |v| break :blk .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = v[member_id] } } }, @@ -1368,6 +1369,38 @@ fn opConstantComposite(allocator: std.mem.Allocator, _: SpvWord, rt: *Runtime) R for (values.*) |*element| { copyValue(element, try rt.mod.results[try rt.it.next()].getValue()); } + return; + } + + switch (target_value.*) { + .Vector4f32 => |*v| inline for (0..4) |i| { + v[i] = (try rt.mod.results[try rt.it.next()].getValue()).Float.value.float32; + }, + .Vector3f32 => |*v| inline for (0..3) |i| { + v[i] = (try rt.mod.results[try rt.it.next()].getValue()).Float.value.float32; + }, + .Vector2f32 => |*v| inline for (0..2) |i| { + v[i] = (try rt.mod.results[try rt.it.next()].getValue()).Float.value.float32; + }, + .Vector4i32 => |*v| inline for (0..4) |i| { + v[i] = (try rt.mod.results[try rt.it.next()].getValue()).Int.value.sint32; + }, + .Vector3i32 => |*v| inline for (0..3) |i| { + v[i] = (try rt.mod.results[try rt.it.next()].getValue()).Int.value.sint32; + }, + .Vector2i32 => |*v| inline for (0..2) |i| { + v[i] = (try rt.mod.results[try rt.it.next()].getValue()).Int.value.sint32; + }, + .Vector4u32 => |*v| inline for (0..4) |i| { + v[i] = (try rt.mod.results[try rt.it.next()].getValue()).Int.value.uint32; + }, + .Vector3u32 => |*v| inline for (0..3) |i| { + v[i] = (try rt.mod.results[try rt.it.next()].getValue()).Int.value.uint32; + }, + .Vector2u32 => |*v| inline for (0..2) |i| { + v[i] = (try rt.mod.results[try rt.it.next()].getValue()).Int.value.uint32; + }, + else => return RuntimeError.InvalidSpirV, } }