From fe47277468c694b10153282761efd3d6f90d8f6a Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Fri, 20 Mar 2026 03:14:36 +0100 Subject: [PATCH] adding array stride to runtime arrays --- src/Result.zig | 72 ++----------------------------------------------- src/Value.zig | 24 +++++++++++++++-- src/opcodes.zig | 43 +++++++++++++---------------- 3 files changed, 43 insertions(+), 96 deletions(-) diff --git a/src/Result.zig b/src/Result.zig index faea1ef..baf5e81 100644 --- a/src/Result.zig +++ b/src/Result.zig @@ -116,6 +116,7 @@ pub const TypeData = union(Type) { RuntimeArray: struct { components_type_word: SpvWord, components_type: Type, + stride: SpvWord, }, Structure: struct { members_type_word: []const SpvWord, @@ -142,7 +143,7 @@ pub const TypeData = union(Type) { .Vector => |v| results[v.components_type_word].variant.?.Type.getSize(results), .Array => |a| results[a.components_type_word].variant.?.Type.getSize(results), .Matrix => |m| results[m.column_type_word].variant.?.Type.getSize(results), - .RuntimeArray => |a| results[a.components_type_word].variant.?.Type.getSize(results), + .RuntimeArray => |a| a.stride, .Structure => |s| blk: { var total: usize = 0; for (s.members_type_word) |type_word| { @@ -425,75 +426,6 @@ pub fn getMemberCounts(self: *const Self) usize { return 0; } -pub fn initValue(allocator: std.mem.Allocator, member_count: usize, results: []const Self, resolved: *const Self) RuntimeError!Value { - return switch (resolved.variant.?) { - .Type => |t| switch (t) { - .Void => .{ .Void = .{} }, - .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: { - const value: Value = .{ .Vector = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory }; - errdefer allocator.free(value.Vector); - for (value.Vector) |*val| { - val.* = try Value.init(allocator, results, v.components_type_word); - } - break :blk value; - }, - .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: { - const value: Value = .{ .Matrix = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory }; - errdefer allocator.free(value.Matrix); - for (value.Matrix) |*v| { - v.* = try Value.init(allocator, results, m.column_type_word); - } - break :blk value; - }, - .Array => |a| blk: { - const value: Value = .{ .Array = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory }; - errdefer allocator.free(value.Array); - for (value.Array) |*val| { - val.* = try Value.init(allocator, results, a.components_type_word); - } - break :blk value; - }, - .RuntimeArray => |a| .{ - .RuntimeArray = .{ - .type_word = a.components_type_word, - .data = &.{}, - }, - }, - .Structure => |s| blk: { - const value: Value = .{ .Structure = allocator.alloc(Value, member_count) catch return RuntimeError.OutOfMemory }; - errdefer allocator.free(value.Structure); - for (value.Structure, s.members_type_word) |*v, member_type_word| { - v.* = try Value.init(allocator, results, member_type_word); - } - break :blk value; - }, - .Image => RuntimeError.ToDo, - .Sampler => RuntimeError.ToDo, - .SampledImage => RuntimeError.ToDo, - else => RuntimeError.InvalidSpirV, - }, - else => RuntimeError.InvalidSpirV, - }; -} - pub fn flushPtr(self: *Self, allocator: std.mem.Allocator) RuntimeError!void { if (self.variant) |*variant| { switch (variant.*) { diff --git a/src/Value.zig b/src/Value.zig index a62d069..2ddb141 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -64,7 +64,22 @@ pub const Value = union(Type) { Array: []Self, RuntimeArray: struct { type_word: SpvWord, + stride: SpvWord, data: []u8, + + pub inline fn createValueFromIndex(self: *const @This(), allocator: std.mem.Allocator, results: []Result, index: usize) RuntimeError!*Value { + const value = allocator.create(Value) catch return RuntimeError.OutOfMemory; + errdefer allocator.destroy(value); + + value.* = try Value.init(allocator, results, self.type_word); + _ = try value.writeConst(self.data[(try self.getOffsetOfIndex(index))..]); + + return value; + } + + pub inline fn getOffsetOfIndex(self: *const @This(), index: usize) RuntimeError!usize { + return self.stride * index; + } }, Structure: []Self, Function: noreturn, @@ -94,6 +109,7 @@ pub const Value = union(Type) { return switch (resolved.variant.?) { .Type => |t| switch (t) { + .Void => .{ .Void = .{} }, .Bool => .{ .Bool = false }, .Int => |i| .{ .Int = .{ .bit_count = i.bit_length, @@ -151,12 +167,16 @@ pub const Value = union(Type) { .RuntimeArray => |a| .{ .RuntimeArray = .{ .type_word = a.components_type_word, + .stride = a.stride, .data = &.{}, }, }, - else => unreachable, + .Image => RuntimeError.ToDo, + .Sampler => RuntimeError.ToDo, + .SampledImage => RuntimeError.ToDo, + else => RuntimeError.InvalidSpirV, }, - else => unreachable, + else => RuntimeError.InvalidSpirV, }; } diff --git a/src/opcodes.zig b/src/opcodes.zig index f004141..7670d32 100644 --- a/src/opcodes.zig +++ b/src/opcodes.zig @@ -1206,21 +1206,14 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime switch (value_ptr.*) { .Vector, .Matrix, .Array, .Structure => |v| { - if (i.value.uint32 >= v.len) return RuntimeError.OutOfBounds; + if (i.value.uint32 >= v.len) + return RuntimeError.OutOfBounds; value_ptr = &v[i.value.uint32]; }, .RuntimeArray => |*arr| { - 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(Value) catch return RuntimeError.OutOfMemory; - errdefer concrete_allocator.destroy(value_ptr); - - value_ptr.* = try Value.init(concrete_allocator, rt.results, arr.type_word); - _ = try value_ptr.writeConst(arr.data[(type_size * i.value.uint32)..]); - + value_ptr = try arr.createValueFromIndex(if (is_last) allocator else arena_allocator, rt.results, i.value.uint32); if (is_last) - runtime_array_window = arr.data[(type_size * i.value.uint32)..]; + runtime_array_window = arr.data[(try arr.getOffsetOfIndex(i.value.uint32))..]; }, .Vector4f32 => |*v| { if (i.value.uint32 > 4) return RuntimeError.OutOfBounds; @@ -1320,13 +1313,12 @@ fn opCompositeConstruct(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) switch (value.*) { .RuntimeArray => |arr| { - const type_size = (try rt.results[arr.type_word].getVariant()).Type.getSize(rt.results); var offset: usize = 0; for (0..index_count) |_| { const elem_value = (try rt.results[try rt.it.next()].getVariant()).Constant.value; - std.mem.copyForwards(u8, arr.data[offset..(offset + type_size)], std.mem.asBytes(&elem_value)); - offset += type_size; + std.mem.copyForwards(u8, arr.data[offset..(offset + arr.stride)], std.mem.asBytes(&elem_value)); + offset += arr.stride; } }, .Vector4f32 => |*vec| inline for (0..4) |i| { @@ -1388,9 +1380,8 @@ 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 Value.init(arena_allocator, rt.results, arr.type_word); - _ = try composite.writeConst(arr.data[(type_size * member_id)..]); + _ = try composite.writeConst(arr.data[(try arr.getOffsetOfIndex(member_id))..]); }, .Vector4f32 => |v| break :blk .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = v[member_id] } } }, .Vector3f32 => |v| break :blk .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = v[member_id] } } }, @@ -2006,14 +1997,20 @@ fn opTypePointer(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!vo fn opTypeRuntimeArray(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { const id = try rt.it.next(); + var target = &rt.mod.results[id]; const components_type_word = try rt.it.next(); - rt.mod.results[id].variant = .{ + const components_type_data = &((try rt.mod.results[components_type_word].getVariant()).*).Type; + target.variant = .{ .Type = .{ .RuntimeArray = .{ .components_type_word = components_type_word, - .components_type = switch ((try rt.mod.results[components_type_word].getVariant()).*) { - .Type => |t| @as(Result.Type, t), - else => return RuntimeError.InvalidSpirV, + .components_type = @as(Result.Type, components_type_data.*), + .stride = blk: { + for (target.decorations.items) |decoration| { + if (decoration.rtype == .ArrayStride) + break :blk decoration.literal_1; + } + break :blk @intCast(components_type_data.getSize(rt.mod.results)); }, }, }, @@ -2121,7 +2118,6 @@ fn opVariable(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) R const resolved_word = if (rt.mod.results[var_type].resolveTypeWordOrNull()) |word| word else var_type; const resolved = &rt.mod.results[resolved_word]; - const member_count = resolved.getMemberCounts(); target.variant = .{ .Variable = .{ .storage_class = storage_class, @@ -2130,7 +2126,7 @@ fn opVariable(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) R .Type => |t| @as(Result.Type, t), else => return RuntimeError.InvalidSpirV, }, - .value = try Result.initValue(allocator, member_count, rt.mod.results, resolved), + .value = try Value.init(allocator, rt.mod.results, resolved_word), }, }; @@ -2171,10 +2167,9 @@ fn setupConstant(allocator: std.mem.Allocator, rt: *Runtime) RuntimeError!*Resul const target = &rt.mod.results[id]; const resolved = rt.mod.results[res_type].resolveType(rt.mod.results); - const member_count = resolved.getMemberCounts(); target.variant = .{ .Constant = .{ - .value = try Result.initValue(allocator, member_count, rt.mod.results, resolved), + .value = try Value.init(allocator, rt.mod.results, res_type), .type_word = res_type, .type = switch ((try resolved.getConstVariant()).*) { .Type => |t| @as(Result.Type, t),