yes
Build / build (push) Successful in 32s
Test / build (push) Successful in 1m3s

This commit is contained in:
2026-06-04 02:44:40 +02:00
parent 431a634290
commit 8677e8a683
3 changed files with 312 additions and 65 deletions
+148 -8
View File
@@ -94,6 +94,16 @@ pub fn init(allocator: std.mem.Allocator, module: *Module, image_api: ImageAPI)
const results = allocator.dupe(Result, module.results) catch return RuntimeError.OutOfMemory; const results = allocator.dupe(Result, module.results) catch return RuntimeError.OutOfMemory;
for (results, module.results) |*new_result, result| { for (results, module.results) |*new_result, result| {
new_result.* = result.dupe(allocator) catch return RuntimeError.OutOfMemory; new_result.* = result.dupe(allocator) catch return RuntimeError.OutOfMemory;
if (new_result.variant) |*variant| {
switch (variant.*) {
.AccessChain => |*access_chain| {
allocator.free(access_chain.indexes);
access_chain.value.deinit(allocator);
new_result.variant = null;
},
else => {},
}
}
} }
break :blk results; break :blk results;
}, },
@@ -192,13 +202,13 @@ 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 /// 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 { pub inline fn callEntryPoint(self: *Self, allocator: std.mem.Allocator, entry_point_index: SpvWord) RuntimeError!void {
_ = try self.beginEntryPoint(allocator, entry_point_index); _ = try self.beginEntryPoint(allocator, entry_point_index);
} }
pub fn beginEntryPoint(self: *Self, allocator: std.mem.Allocator, entry_point_index: SpvWord) RuntimeError!EntryPointStatus { pub fn beginEntryPoint(self: *Self, allocator: std.mem.Allocator, entry_point_index: SpvWord) RuntimeError!EntryPointStatus {
self.reset(); self.reset();
if (entry_point_index > self.mod.entry_points.items.len) if (entry_point_index >= self.mod.entry_points.items.len)
return RuntimeError.InvalidEntryPoint; return RuntimeError.InvalidEntryPoint;
// Spec constants pass // Spec constants pass
@@ -307,9 +317,18 @@ fn readResultValue(self: *const Self, output: []u8, result: SpvWord) RuntimeErro
.AccessChain => |a| switch (a.value) { .AccessChain => |a| switch (a.value) {
.Pointer => |ptr| switch (ptr.ptr) { .Pointer => |ptr| switch (ptr.ptr) {
.common => |value_ptr| _ = try value_ptr.read(output), .common => |value_ptr| _ = try value_ptr.read(output),
.f32_ptr => |value_ptr| std.mem.copyForwards(u8, output[0..@sizeOf(f32)], std.mem.asBytes(value_ptr)), .f32_ptr => |value_ptr| {
.i32_ptr => |value_ptr| std.mem.copyForwards(u8, output[0..@sizeOf(i32)], std.mem.asBytes(value_ptr)), if (output.len < @sizeOf(f32)) return RuntimeError.OutOfBounds;
.u32_ptr => |value_ptr| std.mem.copyForwards(u8, output[0..@sizeOf(u32)], std.mem.asBytes(value_ptr)), std.mem.copyForwards(u8, output[0..@sizeOf(f32)], std.mem.asBytes(value_ptr));
},
.i32_ptr => |value_ptr| {
if (output.len < @sizeOf(i32)) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, output[0..@sizeOf(i32)], std.mem.asBytes(value_ptr));
},
.u32_ptr => |value_ptr| {
if (output.len < @sizeOf(u32)) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, output[0..@sizeOf(u32)], std.mem.asBytes(value_ptr));
},
}, },
else => _ = try a.value.read(output), else => _ = try a.value.read(output),
}, },
@@ -324,9 +343,18 @@ fn writeResultValue(self: *const Self, input: []const u8, result: SpvWord) Runti
.AccessChain => |*a| switch (a.value) { .AccessChain => |*a| switch (a.value) {
.Pointer => |ptr| switch (ptr.ptr) { .Pointer => |ptr| switch (ptr.ptr) {
.common => |value_ptr| _ = try value_ptr.write(input), .common => |value_ptr| _ = try value_ptr.write(input),
.f32_ptr => |value_ptr| std.mem.copyForwards(u8, std.mem.asBytes(value_ptr), input[0..@sizeOf(f32)]), .f32_ptr => |value_ptr| {
.i32_ptr => |value_ptr| std.mem.copyForwards(u8, std.mem.asBytes(value_ptr), input[0..@sizeOf(i32)]), if (input.len < @sizeOf(f32)) return RuntimeError.OutOfBounds;
.u32_ptr => |value_ptr| std.mem.copyForwards(u8, std.mem.asBytes(value_ptr), input[0..@sizeOf(u32)]), std.mem.copyForwards(u8, std.mem.asBytes(value_ptr), input[0..@sizeOf(f32)]);
},
.i32_ptr => |value_ptr| {
if (input.len < @sizeOf(i32)) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(value_ptr), input[0..@sizeOf(i32)]);
},
.u32_ptr => |value_ptr| {
if (input.len < @sizeOf(u32)) return RuntimeError.OutOfBounds;
std.mem.copyForwards(u8, std.mem.asBytes(value_ptr), input[0..@sizeOf(u32)]);
},
}, },
else => _ = try a.value.write(input), else => _ = try a.value.write(input),
}, },
@@ -337,6 +365,69 @@ fn writeResultValue(self: *const Self, input: []const u8, result: SpvWord) Runti
} }
} }
const InputLocationTarget = struct {
result: SpvWord,
matrix_column: ?usize = null,
};
fn resolveInputLocationTarget(self: *const Self, location: SpvWord) RuntimeError!InputLocationTarget {
if (location < self.mod.input_locations.len and self.mod.input_locations[location] != 0) {
const result = self.mod.input_locations[location];
const value = try self.results[result].getConstValue();
switch (value.*) {
.Matrix => return .{ .result = result, .matrix_column = 0 },
else => return .{ .result = result },
}
}
var base_location = location;
while (base_location > 0) {
base_location -= 1;
const result = if (base_location < self.mod.input_locations.len)
self.mod.input_locations[base_location]
else
0;
if (result == 0) continue;
const location_offset: usize = @intCast(location - base_location);
const value = try self.results[result].getConstValue();
switch (value.*) {
.Matrix => |columns| {
if (location_offset < columns.len) {
return .{
.result = result,
.matrix_column = location_offset,
};
}
},
else => {},
}
}
return RuntimeError.NotFound;
}
fn getInputLocationTargetValue(self: *const Self, target: InputLocationTarget) RuntimeError!*@import("Value.zig").Value {
const value = switch ((try self.results[target.result].getVariant()).*) {
.Variable => |*v| &v.value,
.AccessChain => |*a| &a.value,
else => return RuntimeError.InvalidSpirV,
};
if (target.matrix_column) |column| {
switch (value.*) {
.Matrix => |columns| {
if (column >= columns.len) return RuntimeError.OutOfBounds;
return &columns[column];
},
else => return RuntimeError.InvalidValueType,
}
}
return value;
}
pub fn readOutput(self: *const Self, output: []u8, result: SpvWord) RuntimeError!void { pub fn readOutput(self: *const Self, output: []u8, result: SpvWord) RuntimeError!void {
if (std.mem.indexOfScalar(SpvWord, &self.mod.output_locations, result)) |_| { if (std.mem.indexOfScalar(SpvWord, &self.mod.output_locations, result)) |_| {
try self.readResultValue(output, result); try self.readResultValue(output, result);
@@ -356,11 +447,28 @@ pub fn readBuiltIn(self: *const Self, output: []u8, builtin: spv.SpvBuiltIn) Run
pub fn writeInput(self: *const Self, input: []const u8, result: SpvWord) RuntimeError!void { pub fn writeInput(self: *const Self, input: []const u8, result: SpvWord) RuntimeError!void {
if (std.mem.indexOfScalar(SpvWord, &self.mod.input_locations, result)) |_| { if (std.mem.indexOfScalar(SpvWord, &self.mod.input_locations, result)) |_| {
try self.writeResultValue(input, result); try self.writeResultValue(input, result);
if (self.results[result].variant) |*variant| switch (variant.*) {
.Variable => |*v| v.value.clearExternalData(),
.AccessChain => |*a| a.value.clearExternalData(),
else => {},
};
} else { } else {
return RuntimeError.NotFound; return RuntimeError.NotFound;
} }
} }
pub fn getInputLocationMemorySize(self: *const Self, location: SpvWord) RuntimeError!usize {
const target = try self.resolveInputLocationTarget(location);
return (try self.getInputLocationTargetValue(target)).getPlainMemorySize();
}
pub fn writeInputLocation(self: *const Self, input: []const u8, location: SpvWord) RuntimeError!void {
const target = try self.resolveInputLocationTarget(location);
const value = try self.getInputLocationTargetValue(target);
_ = try value.write(input);
value.clearExternalData();
}
pub fn writeBuiltIn(self: *const Self, input: []const u8, builtin: spv.SpvBuiltIn) RuntimeError!void { pub fn writeBuiltIn(self: *const Self, input: []const u8, builtin: spv.SpvBuiltIn) RuntimeError!void {
if (self.mod.builtins.get(builtin)) |result| { if (self.mod.builtins.get(builtin)) |result| {
try self.writeResultValue(input, result); try self.writeResultValue(input, result);
@@ -388,8 +496,40 @@ pub fn hasResultDecoration(self: *const Self, result: SpvWord, decoration: spv.S
return false; return false;
} }
pub fn resetInvocation(self: *Self, allocator: std.mem.Allocator) void {
for (self.results) |*result| {
if (result.variant) |*variant| {
switch (variant.*) {
.AccessChain => |*access_chain| {
access_chain.value.flushPtr(allocator) catch {};
},
else => {},
}
}
}
for (self.results) |*result| {
if (result.variant) |*variant| {
switch (variant.*) {
.AccessChain => |*access_chain| {
access_chain.value.deinit(allocator);
allocator.free(access_chain.indexes);
result.variant = null;
},
.FunctionParameter => |*parameter| {
parameter.value_ptr = null;
},
else => {},
}
}
}
self.reset();
}
fn reset(self: *Self) void { fn reset(self: *Self) void {
self.function_stack.clearRetainingCapacity(); self.function_stack.clearRetainingCapacity();
self.current_parameter_index = 0;
self.current_function = null; self.current_function = null;
self.current_label = null; self.current_label = null;
self.previous_label = null; self.previous_label = null;
+137 -53
View File
@@ -80,18 +80,22 @@ pub const Value = union(Type) {
data: []u8, data: []u8,
pub inline fn createValueFromIndex(self: *const @This(), allocator: std.mem.Allocator, results: []const Result, index: usize) RuntimeError!*Value { pub inline fn createValueFromIndex(self: *const @This(), allocator: std.mem.Allocator, results: []const Result, index: usize) RuntimeError!*Value {
const offset = try self.getCheckedOffsetOfIndex(index);
const value = allocator.create(Value) catch return RuntimeError.OutOfMemory; const value = allocator.create(Value) catch return RuntimeError.OutOfMemory;
errdefer allocator.destroy(value); errdefer allocator.destroy(value);
value.* = try Value.init(allocator, results, self.type_word, false); value.* = try Value.init(allocator, results, self.type_word, false);
_ = try value.write(self.data[self.getOffsetOfIndex(index)..]); errdefer value.deinit(allocator);
_ = try value.write(self.data[offset .. offset + self.stride]);
return value; return value;
} }
pub inline fn createLocalValueFromIndex(self: *const @This(), allocator: std.mem.Allocator, results: []const Result, index: usize) RuntimeError!Value { pub inline fn createLocalValueFromIndex(self: *const @This(), allocator: std.mem.Allocator, results: []const Result, index: usize) RuntimeError!Value {
const offset = try self.getCheckedOffsetOfIndex(index);
var value = try Value.init(allocator, results, self.type_word, false); var value = try Value.init(allocator, results, self.type_word, false);
_ = try value.write(self.data[self.getOffsetOfIndex(index)..]); errdefer value.deinit(allocator);
_ = try value.write(self.data[offset .. offset + self.stride]);
return value; return value;
} }
@@ -99,7 +103,15 @@ pub const Value = union(Type) {
return self.stride * index; return self.stride * index;
} }
pub inline fn getCheckedOffsetOfIndex(self: *const @This(), index: usize) RuntimeError!usize {
const offset = self.getOffsetOfIndex(index);
if (self.stride == 0 or offset > self.data.len or self.stride > self.data.len - offset)
return RuntimeError.OutOfBounds;
return offset;
}
pub inline fn getLen(self: *const @This()) usize { pub inline fn getLen(self: *const @This()) usize {
if (self.stride == 0) return 0;
return @divTrunc(self.data.len, self.stride); return @divTrunc(self.data.len, self.stride);
} }
}, },
@@ -145,6 +157,7 @@ pub const Value = union(Type) {
/// array element. This may differ from ptr.common when the pointer is /// array element. This may differ from ptr.common when the pointer is
/// to a child/member of that materialized value. /// to a child/member of that materialized value.
uniform_backing_value: ?*Self = null, uniform_backing_value: ?*Self = null,
owns_uniform_backing_value: bool = false,
}, },
pub inline fn getCompositeDataOrNull(self: *const Self) ?[]Self { pub inline fn getCompositeDataOrNull(self: *const Self) ?[]Self {
@@ -330,40 +343,54 @@ pub const Value = union(Type) {
const vecRoutine = struct { const vecRoutine = struct {
inline fn routine(comptime T: type, vec: T, out: []u8) RuntimeError!usize { inline fn routine(comptime T: type, vec: T, out: []u8) RuntimeError!usize {
const size = @typeInfo(T).vector.len * 4; const size = @typeInfo(T).vector.len * 4;
if (size >= out.len) { if (out.len < size) return RuntimeError.OutOfBounds;
const range = @typeInfo(T).vector.len; std.mem.bytesAsValue(T, out[0..size]).* = vec;
inline for (0..range) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= out.len or end > out.len) return i * 4;
@memcpy(out[start..end], std.mem.asBytes(&vec[i]));
}
}
std.mem.bytesAsValue(T, out[0..]).* = vec;
return size; return size;
} }
}.routine; }.routine;
switch (self.*) { switch (self.*) {
.Bool => |b| { .Bool => |b| {
if (output.len < 1) return RuntimeError.OutOfBounds;
output[0] = if (b == true) 1 else 0; output[0] = if (b == true) 1 else 0;
return 1; return 1;
}, },
.Int => |i| { .Int => |i| {
switch (i.bit_count) { switch (i.bit_count) {
8 => output[0] = @bitCast(i.value.uint8), 8 => {
16 => @memcpy(output[0..2], std.mem.asBytes(&i.value.uint16)), if (output.len < 1) return RuntimeError.OutOfBounds;
32 => @memcpy(output[0..4], std.mem.asBytes(&i.value.uint32)), output[0] = @bitCast(i.value.uint8);
64 => @memcpy(output[0..8], std.mem.asBytes(&i.value.uint64)), },
16 => {
if (output.len < 2) return RuntimeError.OutOfBounds;
@memcpy(output[0..2], std.mem.asBytes(&i.value.uint16));
},
32 => {
if (output.len < 4) return RuntimeError.OutOfBounds;
@memcpy(output[0..4], std.mem.asBytes(&i.value.uint32));
},
64 => {
if (output.len < 8) return RuntimeError.OutOfBounds;
@memcpy(output[0..8], std.mem.asBytes(&i.value.uint64));
},
else => return RuntimeError.InvalidValueType, else => return RuntimeError.InvalidValueType,
} }
return @divExact(i.bit_count, 8); return @divExact(i.bit_count, 8);
}, },
.Float => |f| { .Float => |f| {
switch (f.bit_count) { switch (f.bit_count) {
16 => @memcpy(output[0..2], std.mem.asBytes(&f.value.float16)), 16 => {
32 => @memcpy(output[0..4], std.mem.asBytes(&f.value.float32)), if (output.len < 2) return RuntimeError.OutOfBounds;
64 => @memcpy(output[0..8], std.mem.asBytes(&f.value.float64)), @memcpy(output[0..2], std.mem.asBytes(&f.value.float16));
},
32 => {
if (output.len < 4) return RuntimeError.OutOfBounds;
@memcpy(output[0..4], std.mem.asBytes(&f.value.float32));
},
64 => {
if (output.len < 8) return RuntimeError.OutOfBounds;
@memcpy(output[0..8], std.mem.asBytes(&f.value.float64));
},
else => return RuntimeError.InvalidValueType, else => return RuntimeError.InvalidValueType,
} }
return @divExact(f.bit_count, 8); return @divExact(f.bit_count, 8);
@@ -400,6 +427,7 @@ pub const Value = union(Type) {
var end_offset: usize = 0; var end_offset: usize = 0;
for (s.values, 0..) |v, i| { for (s.values, 0..) |v, i| {
const member_offset: usize = @intCast(s.offsets[i] orelse end_offset); const member_offset: usize = @intCast(s.offsets[i] orelse end_offset);
if (member_offset > output.len) return RuntimeError.OutOfBounds;
const read_size = try v.read(output[member_offset..]); const read_size = try v.read(output[member_offset..]);
end_offset = @max(end_offset, member_offset + read_size); end_offset = @max(end_offset, member_offset + read_size);
} }
@@ -415,40 +443,54 @@ pub const Value = union(Type) {
const vecRoutine = struct { const vecRoutine = struct {
inline fn routine(comptime T: type, vec: *T, in: []const u8) RuntimeError!usize { inline fn routine(comptime T: type, vec: *T, in: []const u8) RuntimeError!usize {
const size = @typeInfo(T).vector.len * 4; const size = @typeInfo(T).vector.len * 4;
if (size >= in.len) { if (in.len < size) return RuntimeError.OutOfBounds;
const range = @typeInfo(T).vector.len; vec.* = std.mem.bytesToValue(T, in[0..size]);
inline for (0..range) |i| {
const start = i * 4;
const end = (i + 1) * 4;
if (start >= in.len or end > in.len) return i * 4;
@memcpy(std.mem.asBytes(&vec[i]), in[start..end]);
}
}
vec.* = std.mem.bytesToValue(T, in[0..]);
return size; return size;
} }
}.routine; }.routine;
switch (self.*) { switch (self.*) {
.Bool => |*b| { .Bool => |*b| {
if (input.len < 1) return RuntimeError.OutOfBounds;
b.* = if (input[0] != 0) true else false; b.* = if (input[0] != 0) true else false;
return 1; return 1;
}, },
.Int => |*i| { .Int => |*i| {
switch (i.bit_count) { switch (i.bit_count) {
8 => i.value.uint8 = @bitCast(input[0]), 8 => {
16 => @memcpy(std.mem.asBytes(&i.value.uint16), input[0..2]), if (input.len < 1) return RuntimeError.OutOfBounds;
32 => @memcpy(std.mem.asBytes(&i.value.uint32), input[0..4]), i.value.uint8 = @bitCast(input[0]);
64 => @memcpy(std.mem.asBytes(&i.value.uint64), input[0..8]), },
16 => {
if (input.len < 2) return RuntimeError.OutOfBounds;
@memcpy(std.mem.asBytes(&i.value.uint16), input[0..2]);
},
32 => {
if (input.len < 4) return RuntimeError.OutOfBounds;
@memcpy(std.mem.asBytes(&i.value.uint32), input[0..4]);
},
64 => {
if (input.len < 8) return RuntimeError.OutOfBounds;
@memcpy(std.mem.asBytes(&i.value.uint64), input[0..8]);
},
else => return RuntimeError.InvalidValueType, else => return RuntimeError.InvalidValueType,
} }
return @divExact(i.bit_count, 8); return @divExact(i.bit_count, 8);
}, },
.Float => |*f| { .Float => |*f| {
switch (f.bit_count) { switch (f.bit_count) {
16 => @memcpy(std.mem.asBytes(&f.value.float16), input[0..2]), 16 => {
32 => @memcpy(std.mem.asBytes(&f.value.float32), input[0..4]), if (input.len < 2) return RuntimeError.OutOfBounds;
64 => @memcpy(std.mem.asBytes(&f.value.float64), input[0..8]), @memcpy(std.mem.asBytes(&f.value.float16), input[0..2]);
},
32 => {
if (input.len < 4) return RuntimeError.OutOfBounds;
@memcpy(std.mem.asBytes(&f.value.float32), input[0..4]);
},
64 => {
if (input.len < 8) return RuntimeError.OutOfBounds;
@memcpy(std.mem.asBytes(&f.value.float64), input[0..8]);
},
else => return RuntimeError.InvalidValueType, else => return RuntimeError.InvalidValueType,
} }
return @divExact(f.bit_count, 8); return @divExact(f.bit_count, 8);
@@ -466,7 +508,25 @@ pub const Value = union(Type) {
.Vector3u32 => |*vec| return vecRoutine(@TypeOf(vec.*), vec, input), .Vector3u32 => |*vec| return vecRoutine(@TypeOf(vec.*), vec, input),
.Vector2u32 => |*vec| return vecRoutine(@TypeOf(vec.*), vec, input), .Vector2u32 => |*vec| return vecRoutine(@TypeOf(vec.*), vec, input),
.Vector, .Matrix => |*values| { .Vector => |*values| {
var offset: usize = 0;
for (values.*) |*v| {
offset += try v.write(input[offset..]);
}
return offset;
},
.Matrix => |*values| {
const matrix_stride = 16;
if (values.len != 0) {
const column_size = try values.*[0].getPlainMemorySize();
if (column_size < matrix_stride and input.len >= (values.len - 1) * matrix_stride + column_size) {
for (values.*, 0..) |*v, column| {
_ = try v.write(input[column * matrix_stride ..]);
}
return (values.len - 1) * matrix_stride + column_size;
}
}
var offset: usize = 0; var offset: usize = 0;
for (values.*) |*v| { for (values.*) |*v| {
offset += try v.write(input[offset..]); offset += try v.write(input[offset..]);
@@ -485,24 +545,49 @@ pub const Value = union(Type) {
var end_offset: usize = 0; var end_offset: usize = 0;
for (s.values, 0..) |*v, i| { for (s.values, 0..) |*v, i| {
const member_offset: usize = @intCast(s.offsets[i] orelse end_offset); const member_offset: usize = @intCast(s.offsets[i] orelse end_offset);
if (member_offset > input.len) return RuntimeError.OutOfBounds;
const write_size = try v.write(input[member_offset..]); const write_size = try v.write(input[member_offset..]);
end_offset = @max(end_offset, member_offset + write_size); end_offset = @max(end_offset, member_offset + write_size);
} }
if (end_offset > input.len) return RuntimeError.OutOfBounds;
s.external_data = @constCast(input[0..end_offset]); s.external_data = @constCast(input[0..end_offset]);
return end_offset; return end_offset;
}, },
.RuntimeArray => |*arr| arr.data = @constCast(input[0..]), .RuntimeArray => |*arr| arr.data = @constCast(input[0..]),
.Image => |*img| img.driver_image = @ptrFromInt(std.mem.bytesToValue(usize, input[0..])), .Image => |*img| {
.Sampler => |*sampler| sampler.driver_sampler = @ptrFromInt(std.mem.bytesToValue(usize, input[0..])), if (input.len < @sizeOf(usize)) return RuntimeError.OutOfBounds;
img.driver_image = @ptrFromInt(std.mem.bytesToValue(usize, input[0..@sizeOf(usize)]));
},
.Sampler => |*sampler| {
if (input.len < @sizeOf(usize)) return RuntimeError.OutOfBounds;
sampler.driver_sampler = @ptrFromInt(std.mem.bytesToValue(usize, input[0..@sizeOf(usize)]));
},
.SampledImage => |*img| { .SampledImage => |*img| {
img.driver_image = @ptrFromInt(std.mem.bytesToValue(usize, input[0..])); if (input.len < @sizeOf(usize) * 2) return RuntimeError.OutOfBounds;
img.driver_sampler = @ptrFromInt(std.mem.bytesToValue(usize, input[@sizeOf(usize)..])); img.driver_image = @ptrFromInt(std.mem.bytesToValue(usize, input[0..@sizeOf(usize)]));
img.driver_sampler = @ptrFromInt(std.mem.bytesToValue(usize, input[@sizeOf(usize)..][0..@sizeOf(usize)]));
}, },
else => return RuntimeError.InvalidValueType, else => return RuntimeError.InvalidValueType,
} }
return 0; return 0;
} }
pub fn clearExternalData(self: *Self) void {
switch (self.*) {
.Vector, .Matrix => |values| {
for (values) |*value| value.clearExternalData();
},
.Array => |*arr| {
for (arr.values) |*value| value.clearExternalData();
},
.Structure => |*s| {
s.external_data = null;
for (s.values) |*value| value.clearExternalData();
},
else => {},
}
}
pub fn getPlainMemorySize(self: *const Self) RuntimeError!usize { pub fn getPlainMemorySize(self: *const Self) RuntimeError!usize {
return switch (self.*) { return switch (self.*) {
.Bool => 1, .Bool => 1,
@@ -568,6 +653,7 @@ pub const Value = union(Type) {
} }
pub fn flushPtr(self: *Self, allocator: std.mem.Allocator) RuntimeError!void { pub fn flushPtr(self: *Self, allocator: std.mem.Allocator) RuntimeError!void {
_ = allocator;
switch (self.*) { switch (self.*) {
.Pointer => |*p| { .Pointer => |*p| {
if (p.uniform_slice_window) |window| { if (p.uniform_slice_window) |window| {
@@ -589,20 +675,8 @@ pub const Value = union(Type) {
}, },
} }
if (p.uniform_backing_value) |backing| {
backing.deinit(allocator);
allocator.destroy(backing);
p.uniform_backing_value = null;
}
p.uniform_slice_window = null; p.uniform_slice_window = null;
} }
if (p.uniform_backing_value) |backing| {
backing.deinit(allocator);
allocator.destroy(backing);
p.uniform_backing_value = null;
}
}, },
else => {}, else => {},
} }
@@ -623,6 +697,16 @@ pub const Value = union(Type) {
allocator.free(s.values); allocator.free(s.values);
allocator.free(s.offsets); allocator.free(s.offsets);
}, },
.Pointer => |*p| {
if (p.owns_uniform_backing_value) {
if (p.uniform_backing_value) |backing| {
backing.deinit(allocator);
allocator.destroy(backing);
}
}
p.uniform_backing_value = null;
p.owns_uniform_backing_value = false;
},
else => {}, else => {},
} }
} }
+27 -4
View File
@@ -1625,6 +1625,7 @@ fn opImageTexelPointer(allocator: std.mem.Allocator, word_count: SpvWord, rt: *R
if (rt.results[result_id].variant) |*variant| { if (rt.results[result_id].variant) |*variant| {
switch (variant.*) { switch (variant.*) {
.AccessChain => |*a| { .AccessChain => |*a| {
try a.value.flushPtr(allocator);
allocator.free(a.indexes); allocator.free(a.indexes);
a.value.deinit(allocator); a.value.deinit(allocator);
}, },
@@ -1648,6 +1649,7 @@ fn opImageTexelPointer(allocator: std.mem.Allocator, word_count: SpvWord, rt: *R
.z = z, .z = z,
}, },
.uniform_backing_value = backing, .uniform_backing_value = backing,
.owns_uniform_backing_value = true,
} }, } },
}, },
}; };
@@ -1816,7 +1818,12 @@ fn MathEngine(comptime T: PrimitiveType, comptime Op: MathOp, comptime IsAtomic:
fn applySIMDVectorf32(comptime N: usize, d: *@Vector(N, f32), l: *const Value, r: *const Value) RuntimeError!void { fn applySIMDVectorf32(comptime N: usize, d: *@Vector(N, f32), l: *const Value, r: *const Value) RuntimeError!void {
switch (Op) { switch (Op) {
.MatrixTimesVector => inline for (0..N) |i| { .MatrixTimesVector => inline for (0..N) |i| {
d[i] = @reduce(.Add, l.Matrix[i].getVectorSpecialization(N, f32) * r.getVectorSpecialization(N, f32)); const l_vec = l.Matrix[i].getVectorSpecialization(N, f32);
const r_vec = r.getVectorSpecialization(N, f32);
d[i] = 0;
inline for (0..N) |j| {
d[i] += l_vec[j] * r_vec[j];
}
}, },
else => try applyDirectSIMDVectorf32(N, d, l.getVectorSpecialization(N, f32), r), else => try applyDirectSIMDVectorf32(N, d, l.getVectorSpecialization(N, f32), r),
} }
@@ -2048,6 +2055,7 @@ fn setupAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runt
if (rt.results[id].variant) |*variant| { if (rt.results[id].variant) |*variant| {
switch (variant.*) { switch (variant.*) {
.AccessChain => |*a| { .AccessChain => |*a| {
try a.value.flushPtr(allocator);
allocator.free(a.indexes); allocator.free(a.indexes);
a.value.deinit(allocator); a.value.deinit(allocator);
}, },
@@ -2285,11 +2293,13 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
var uniform_slice_window: ?[]u8 = null; var uniform_slice_window: ?[]u8 = null;
var uniform_backing_value: ?*Value = null; var uniform_backing_value: ?*Value = null;
var owns_uniform_backing_value = false;
if (std.meta.activeTag(value_ptr.*) == .Pointer) { if (std.meta.activeTag(value_ptr.*) == .Pointer) {
const ptr = value_ptr.Pointer; const ptr = value_ptr.Pointer;
uniform_slice_window = ptr.uniform_slice_window; uniform_slice_window = ptr.uniform_slice_window;
uniform_backing_value = ptr.uniform_backing_value; uniform_backing_value = ptr.uniform_backing_value;
owns_uniform_backing_value = false;
switch (ptr.ptr) { switch (ptr.ptr) {
.common => |common| value_ptr = common, .common => |common| value_ptr = common,
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
@@ -2312,6 +2322,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
const ptr = value_ptr.Pointer; const ptr = value_ptr.Pointer;
uniform_slice_window = ptr.uniform_slice_window; uniform_slice_window = ptr.uniform_slice_window;
uniform_backing_value = ptr.uniform_backing_value; uniform_backing_value = ptr.uniform_backing_value;
owns_uniform_backing_value = false;
switch (ptr.ptr) { switch (ptr.ptr) {
.common => |common| value_ptr = common, .common => |common| value_ptr = common,
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
@@ -2365,13 +2376,14 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
allocator.destroy(backing); allocator.destroy(backing);
} }
if (uniform_backing_value) |old_backing| { if (owns_uniform_backing_value) if (uniform_backing_value) |old_backing| {
old_backing.deinit(allocator); old_backing.deinit(allocator);
allocator.destroy(old_backing); allocator.destroy(old_backing);
} };
value_ptr = backing; value_ptr = backing;
uniform_backing_value = backing; uniform_backing_value = backing;
owns_uniform_backing_value = true;
uniform_slice_window = arr.data[element_offset .. element_offset + arr.stride]; uniform_slice_window = arr.data[element_offset .. element_offset + arr.stride];
}, },
.Vector4f32 => |*v| switch (component_index) { .Vector4f32 => |*v| switch (component_index) {
@@ -2379,6 +2391,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.ptr = .{ .f32_ptr = &v[idx] }, .ptr = .{ .f32_ptr = &v[idx] },
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(f32), @sizeOf(f32)), .uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(f32), @sizeOf(f32)),
.uniform_backing_value = uniform_backing_value, .uniform_backing_value = uniform_backing_value,
.owns_uniform_backing_value = owns_uniform_backing_value,
} }, } },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -2387,6 +2400,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.ptr = .{ .f32_ptr = &v[idx] }, .ptr = .{ .f32_ptr = &v[idx] },
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(f32), @sizeOf(f32)), .uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(f32), @sizeOf(f32)),
.uniform_backing_value = uniform_backing_value, .uniform_backing_value = uniform_backing_value,
.owns_uniform_backing_value = owns_uniform_backing_value,
} }, } },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -2395,6 +2409,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.ptr = .{ .f32_ptr = &v[idx] }, .ptr = .{ .f32_ptr = &v[idx] },
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(f32), @sizeOf(f32)), .uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(f32), @sizeOf(f32)),
.uniform_backing_value = uniform_backing_value, .uniform_backing_value = uniform_backing_value,
.owns_uniform_backing_value = owns_uniform_backing_value,
} }, } },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -2403,6 +2418,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.ptr = .{ .i32_ptr = &v[idx] }, .ptr = .{ .i32_ptr = &v[idx] },
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(i32), @sizeOf(i32)), .uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(i32), @sizeOf(i32)),
.uniform_backing_value = uniform_backing_value, .uniform_backing_value = uniform_backing_value,
.owns_uniform_backing_value = owns_uniform_backing_value,
} }, } },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -2411,6 +2427,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.ptr = .{ .i32_ptr = &v[idx] }, .ptr = .{ .i32_ptr = &v[idx] },
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(i32), @sizeOf(i32)), .uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(i32), @sizeOf(i32)),
.uniform_backing_value = uniform_backing_value, .uniform_backing_value = uniform_backing_value,
.owns_uniform_backing_value = owns_uniform_backing_value,
} }, } },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -2419,6 +2436,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.ptr = .{ .i32_ptr = &v[idx] }, .ptr = .{ .i32_ptr = &v[idx] },
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(i32), @sizeOf(i32)), .uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(i32), @sizeOf(i32)),
.uniform_backing_value = uniform_backing_value, .uniform_backing_value = uniform_backing_value,
.owns_uniform_backing_value = owns_uniform_backing_value,
} }, } },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -2427,6 +2445,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.ptr = .{ .u32_ptr = &v[idx] }, .ptr = .{ .u32_ptr = &v[idx] },
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(u32), @sizeOf(u32)), .uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(u32), @sizeOf(u32)),
.uniform_backing_value = uniform_backing_value, .uniform_backing_value = uniform_backing_value,
.owns_uniform_backing_value = owns_uniform_backing_value,
} }, } },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -2435,6 +2454,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.ptr = .{ .u32_ptr = &v[idx] }, .ptr = .{ .u32_ptr = &v[idx] },
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(u32), @sizeOf(u32)), .uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(u32), @sizeOf(u32)),
.uniform_backing_value = uniform_backing_value, .uniform_backing_value = uniform_backing_value,
.owns_uniform_backing_value = owns_uniform_backing_value,
} }, } },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -2443,6 +2463,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.ptr = .{ .u32_ptr = &v[idx] }, .ptr = .{ .u32_ptr = &v[idx] },
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(u32), @sizeOf(u32)), .uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, idx * @sizeOf(u32), @sizeOf(u32)),
.uniform_backing_value = uniform_backing_value, .uniform_backing_value = uniform_backing_value,
.owns_uniform_backing_value = owns_uniform_backing_value,
} }, } },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
@@ -2457,6 +2478,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.ptr = .{ .common = value_ptr }, .ptr = .{ .common = value_ptr },
.uniform_slice_window = uniform_slice_window, .uniform_slice_window = uniform_slice_window,
.uniform_backing_value = uniform_backing_value, .uniform_backing_value = uniform_backing_value,
.owns_uniform_backing_value = owns_uniform_backing_value,
}, },
}; };
}, },
@@ -2795,7 +2817,8 @@ fn opCompositeInsert(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Run
return; return;
} }
var elem_value = try arr.createLocalValueFromIndex(alloc, results, elem_offset); var elem_value = try arr.createLocalValueFromIndex(alloc, results, index);
defer elem_value.deinit(alloc);
try insertAt(alloc, results, &elem_value, object_value, indices[1..]); try insertAt(alloc, results, &elem_value, object_value, indices[1..]);
_ = try elem_value.read(arr.data[elem_offset..]); _ = try elem_value.read(arr.data[elem_offset..]);
}, },