From 9c355fe126d0142ac6d1fae48633993864c90d61 Mon Sep 17 00:00:00 2001 From: Kbz-8 Date: Mon, 1 Jun 2026 20:36:24 +0200 Subject: [PATCH] yes --- src/Module.zig | 29 +++++++++++++++++++++++------ src/Runtime.zig | 32 ++++++++++++++++++++++++++++++-- src/opcodes.zig | 18 +++++++++++++++++- 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 08be587..2937a67 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -180,7 +180,7 @@ fn resolveConstantWord(self: *const Self, id: SpvWord) ?SpvWord { } fn findAccessChainToMember(self: *const Self, base_id: SpvWord, member_index: SpvWord) ?SpvWord { - for (self.results, 0..) |result, id| { + for (self.results, 0..) |*result, id| { const variant = result.variant orelse continue; switch (variant) { @@ -265,7 +265,7 @@ fn applyDecorations(self: *Self) ModuleError!void { var binding: ?usize = null; for (result.decorations.items) |decoration| { - switch (result.variant.?) { + if (result.variant) |*variant| switch (variant.*) { .Variable => |v| { try self.applyInterfaceDecoration(v.storage_class, decoration, @intCast(id)); @@ -294,13 +294,30 @@ fn applyDecorations(self: *Self) ModuleError!void { } }, else => {}, - } + }; } - switch (result.variant.?) { - .Variable => |v| try self.applyStructMemberInterfaceDecorations(v.storage_class, v.type_word, @intCast(id)), + if (result.variant) |*variant| switch (variant.*) { + .Variable => |*v| { + try self.applyStructMemberInterfaceDecorations(v.storage_class, v.type_word, @intCast(id)); + switch (v.storage_class) { + .StorageBuffer, + .Uniform, + .PushConstant, + => if (v.value == .Structure) { + if (self.results[v.type_word].variant) |type_variant| switch (type_variant) { + .Type => |type_data| switch (type_data) { + .Structure => |s| @memcpy(@constCast(v.value.Structure.offsets), s.members_offsets), + else => {}, + }, + else => {}, + }; + }, + else => {}, + } + }, else => {}, - } + }; if (set != null and binding != null) { self.bindings[set.?][binding.?] = @intCast(id); diff --git a/src/Runtime.zig b/src/Runtime.zig index 69fdfee..07a49d7 100644 --- a/src/Runtime.zig +++ b/src/Runtime.zig @@ -18,6 +18,7 @@ const WordIterator = @import("WordIterator.zig"); const Self = @This(); pub const RuntimeError = error{ + Barrier, DivisionByZero, InvalidEntryPoint, InvalidSpirV, @@ -33,6 +34,11 @@ pub const RuntimeError = error{ Unknown, }; +pub const EntryPointStatus = enum { + completed, + barrier, +}; + pub const SpecializationEntry = struct { id: SpvWord, offset: usize, @@ -119,6 +125,17 @@ pub fn addSpecializationInfo(self: *Self, allocator: std.mem.Allocator, entry: S self.specialization_constants.put(allocator, entry.id, slice) catch return RuntimeError.OutOfMemory; } +pub fn copySpecializationConstantsFrom(self: *Self, allocator: std.mem.Allocator, other: *const Self) RuntimeError!void { + var it = other.specialization_constants.iterator(); + while (it.next()) |entry| { + const slice = allocator.dupe(u8, entry.value_ptr.*) catch return RuntimeError.OutOfMemory; + self.specialization_constants.put(allocator, entry.key_ptr.*, slice) catch { + allocator.free(slice); + return RuntimeError.OutOfMemory; + }; + } +} + pub fn getEntryPointByName(self: *const Self, name: []const u8) RuntimeError!SpvWord { for (self.mod.entry_points.items, 0..) |entry_point, i| { if (blk: { @@ -176,8 +193,11 @@ pub fn dumpResultsTable(self: *Self, allocator: std.mem.Allocator, writer: *std. /// Calls an entry point, `entry_point_index` being the index of the entry point ordered by declaration in the bytecode pub fn callEntryPoint(self: *Self, allocator: std.mem.Allocator, entry_point_index: SpvWord) RuntimeError!void { - self.reset(); + _ = try self.beginEntryPoint(allocator, entry_point_index); +} +pub fn beginEntryPoint(self: *Self, allocator: std.mem.Allocator, entry_point_index: SpvWord) RuntimeError!EntryPointStatus { + self.reset(); if (entry_point_index > self.mod.entry_points.items.len) return RuntimeError.InvalidEntryPoint; @@ -212,7 +232,15 @@ pub fn callEntryPoint(self: *Self, allocator: std.mem.Allocator, entry_point_ind } // Execution pass - try self.pass(allocator, null); + return self.continueEntryPoint(allocator); +} + +pub fn continueEntryPoint(self: *Self, allocator: std.mem.Allocator) RuntimeError!EntryPointStatus { + self.pass(allocator, null) catch |err| switch (err) { + RuntimeError.Barrier => return .barrier, + else => return err, + }; + return .completed; } fn pass(self: *Self, allocator: std.mem.Allocator, op_set: ?std.EnumSet(spv.SpvOp)) RuntimeError!void { diff --git a/src/opcodes.zig b/src/opcodes.zig index c4b8b3a..ccdcf57 100644 --- a/src/opcodes.zig +++ b/src/opcodes.zig @@ -290,6 +290,7 @@ pub fn initRuntimeDispatcher() void { runtime_dispatcher[@intFromEnum(spv.SpvOp.CompositeConstruct)] = opCompositeConstruct; runtime_dispatcher[@intFromEnum(spv.SpvOp.CompositeExtract)] = opCompositeExtract; runtime_dispatcher[@intFromEnum(spv.SpvOp.CompositeInsert)] = opCompositeInsert; + runtime_dispatcher[@intFromEnum(spv.SpvOp.ControlBarrier)] = opControlBarrier; runtime_dispatcher[@intFromEnum(spv.SpvOp.ConvertFToS)] = ConversionEngine(.Float, .SInt).op; runtime_dispatcher[@intFromEnum(spv.SpvOp.ConvertFToU)] = ConversionEngine(.Float, .UInt).op; runtime_dispatcher[@intFromEnum(spv.SpvOp.ConvertSToF)] = ConversionEngine(.SInt, .Float).op; @@ -349,6 +350,7 @@ pub fn initRuntimeDispatcher() void { runtime_dispatcher[@intFromEnum(spv.SpvOp.MatrixTimesMatrix)] = MathEngine(.Float, .MatrixTimesMatrix, false).op; runtime_dispatcher[@intFromEnum(spv.SpvOp.MatrixTimesScalar)] = MathEngine(.Float, .MatrixTimesScalar, false).op; // TODO runtime_dispatcher[@intFromEnum(spv.SpvOp.MatrixTimesVector)] = MathEngine(.Float, .MatrixTimesVector, false).op; + runtime_dispatcher[@intFromEnum(spv.SpvOp.MemoryBarrier)] = opMemoryBarrier; runtime_dispatcher[@intFromEnum(spv.SpvOp.Not)] = BitEngine(.UInt, .Not).op; runtime_dispatcher[@intFromEnum(spv.SpvOp.Phi)] = opPhi; runtime_dispatcher[@intFromEnum(spv.SpvOp.Return)] = opReturn; @@ -1966,6 +1968,8 @@ fn MathEngine(comptime T: PrimitiveType, comptime Op: MathOp, comptime IsAtomic: fn addDecoration(allocator: std.mem.Allocator, rt: *Runtime, target: SpvWord, decoration_type: spv.SpvDecoration, member: ?SpvWord) RuntimeError!void { var decoration = rt.results[target].decorations.addOne(allocator) catch return RuntimeError.OutOfMemory; decoration.rtype = decoration_type; + decoration.literal_1 = 0; + decoration.literal_2 = null; decoration.index = if (member) |memb| memb else 0; switch (decoration_type) { @@ -2332,7 +2336,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime if (uniform_slice_window != null) { uniform_slice_window = try helpers.advanceWindow(uniform_slice_window, member_offset); } else if (s.external_data) |data| { - uniform_slice_window = data[0..]; + uniform_slice_window = try helpers.advanceWindow(data, member_offset); } value_ptr = &s.values[component_index]; @@ -2502,6 +2506,13 @@ fn opCapability(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!voi rt.mod.capabilities.insert(try rt.it.nextAs(spv.SpvCapability)); } +fn opControlBarrier(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { + _ = rt.it.skip(); // execution scope + _ = rt.it.skip(); // memory scope + _ = rt.it.skip(); // memory semantics + return RuntimeError.Barrier; +} + fn opCompositeConstruct(_: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void { _ = rt.it.skip(); const id = try rt.it.next(); @@ -3498,6 +3509,11 @@ fn opMemoryModel(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!vo rt.mod.memory_model = try rt.it.nextAs(spv.SpvMemoryModel); } +fn opMemoryBarrier(_: std.mem.Allocator, _: SpvWord, rt: *Runtime) RuntimeError!void { + _ = rt.it.skip(); // memory scope + _ = rt.it.skip(); // memory semantics +} + fn opName(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void { const id = try rt.it.next(); var result = &rt.results[id];