improving robust buffer access
Build / build (push) Failing after 1m3s
Test / build (push) Failing after 9m8s

This commit is contained in:
2026-06-29 23:21:38 +02:00
parent fcf303a0c6
commit e49383f07e
3 changed files with 320 additions and 178 deletions
+1 -1
View File
@@ -104,7 +104,7 @@ pub const ImageAPI = struct {
writeImageInt4: *const fn (driver_image: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, pixel: Vec4(u32)) RuntimeError!void, writeImageInt4: *const fn (driver_image: *anyopaque, dim: spv.SpvDim, x: i32, y: i32, z: i32, pixel: Vec4(u32)) RuntimeError!void,
sampleImageFloat4: *const fn (driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32, offset: ImageOffset) RuntimeError!Vec4(f32), sampleImageFloat4: *const fn (driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32, offset: ImageOffset) RuntimeError!Vec4(f32),
sampleImageInt4: *const fn (driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32, offset: ImageOffset) RuntimeError!Vec4(u32), sampleImageInt4: *const fn (driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, lod: ?f32, offset: ImageOffset) RuntimeError!Vec4(u32),
sampleImageDref: *const fn (driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, dref: f32, lod: ?f32, offset: ImageOffset) RuntimeError!f32, sampleImageDref: *const fn (driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, w: f32, dref: f32, lod: ?f32, offset: ImageOffset) RuntimeError!f32,
queryImageSize: *const fn (driver_image: *anyopaque, dim: spv.SpvDim, arrayed: bool, lod: ?i32) RuntimeError!Vec4(u32), queryImageSize: *const fn (driver_image: *anyopaque, dim: spv.SpvDim, arrayed: bool, lod: ?i32) RuntimeError!Vec4(u32),
queryImageLevels: *const fn (driver_image: *anyopaque) RuntimeError!u32, queryImageLevels: *const fn (driver_image: *anyopaque) RuntimeError!u32,
queryImageSamples: *const fn (driver_image: *anyopaque) RuntimeError!u32, queryImageSamples: *const fn (driver_image: *anyopaque) RuntimeError!u32,
+80 -36
View File
@@ -96,6 +96,30 @@ pub const Value = union(Type) {
return value; return value;
} }
pub inline fn createRobustValueFromIndex(self: *const @This(), allocator: std.mem.Allocator, results: []const 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, false);
errdefer value.deinit(allocator);
const bytes = allocator.alloc(u8, self.stride) catch return RuntimeError.OutOfMemory;
defer allocator.free(bytes);
@memset(bytes, 0);
if (self.getRobustOffsetOfIndex(index)) |offset| {
const available = @min(self.stride, self.data.len - offset);
@memcpy(bytes[0..available], self.data[offset .. offset + available]);
}
_ = if (self.matrix_stride) |matrix_stride|
try value.writeWithMatrixLayout(bytes, matrix_stride, self.row_major)
else
try value.write(bytes);
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); 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);
@@ -111,6 +135,12 @@ pub const Value = union(Type) {
return self.stride * index; return self.stride * index;
} }
pub inline fn getRobustOffsetOfIndex(self: *const @This(), index: usize) ?usize {
if (self.stride == 0) return null;
const offset = std.math.mul(usize, self.stride, index) catch return null;
return if (offset < self.data.len) offset else null;
}
pub inline fn getCheckedOffsetOfIndex(self: *const @This(), index: usize) RuntimeError!usize { pub inline fn getCheckedOffsetOfIndex(self: *const @This(), index: usize) RuntimeError!usize {
const offset = self.getOffsetOfIndex(index); const offset = self.getOffsetOfIndex(index);
if (self.stride == 0 or offset > self.data.len or self.stride > self.data.len - offset) if (self.stride == 0 or offset > self.data.len or self.stride > self.data.len - offset)
@@ -540,18 +570,18 @@ pub const Value = union(Type) {
return values[lane_index].write(input); return values[lane_index].write(input);
}, },
.Vector2f32, .Vector3f32, .Vector4f32 => { .Vector2f32, .Vector3f32, .Vector4f32 => {
if (input.len < @sizeOf(f32)) return RuntimeError.OutOfBounds; const value: f32 = if (input.len >= @sizeOf(f32)) std.mem.bytesToValue(f32, input[0..@sizeOf(f32)]) else 0;
try writeLane(.Float, 32, self, lane_index, std.mem.bytesToValue(f32, input[0..@sizeOf(f32)])); try writeLane(.Float, 32, self, lane_index, value);
return @sizeOf(f32); return @sizeOf(f32);
}, },
.Vector2i32, .Vector3i32, .Vector4i32 => { .Vector2i32, .Vector3i32, .Vector4i32 => {
if (input.len < @sizeOf(i32)) return RuntimeError.OutOfBounds; const value: i32 = if (input.len >= @sizeOf(i32)) std.mem.bytesToValue(i32, input[0..@sizeOf(i32)]) else 0;
try writeLane(.SInt, 32, self, lane_index, std.mem.bytesToValue(i32, input[0..@sizeOf(i32)])); try writeLane(.SInt, 32, self, lane_index, value);
return @sizeOf(i32); return @sizeOf(i32);
}, },
.Vector2u32, .Vector3u32, .Vector4u32 => { .Vector2u32, .Vector3u32, .Vector4u32 => {
if (input.len < @sizeOf(u32)) return RuntimeError.OutOfBounds; const value: u32 = if (input.len >= @sizeOf(u32)) std.mem.bytesToValue(u32, input[0..@sizeOf(u32)]) else 0;
try writeLane(.UInt, 32, self, lane_index, std.mem.bytesToValue(u32, input[0..@sizeOf(u32)])); try writeLane(.UInt, 32, self, lane_index, value);
return @sizeOf(u32); return @sizeOf(u32);
}, },
else => return RuntimeError.InvalidValueType, else => return RuntimeError.InvalidValueType,
@@ -651,17 +681,17 @@ pub const Value = union(Type) {
(row_count - 1) * matrix_stride_usize + columns.len * scalar_size (row_count - 1) * matrix_stride_usize + columns.len * scalar_size
else else
(columns.len - 1) * matrix_stride_usize + try columns[0].getPlainMemorySize(); (columns.len - 1) * matrix_stride_usize + try columns[0].getPlainMemorySize();
if (input.len < matrix_size) return RuntimeError.OutOfBounds;
if (row_major) { if (row_major) {
for (columns, 0..) |*column, column_index| { for (columns, 0..) |*column, column_index| {
for (0..row_count) |row_index| { for (0..row_count) |row_index| {
_ = try column.writeVectorLane(row_index, input[row_index * matrix_stride_usize + column_index * scalar_size ..]); const offset = row_index * matrix_stride_usize + column_index * scalar_size;
_ = try column.writeVectorLane(row_index, input[@min(offset, input.len)..]);
} }
} }
} else { } else {
for (columns, 0..) |*column, column_index| { for (columns, 0..) |*column, column_index| {
_ = try column.write(input[column_index * matrix_stride_usize ..]); const offset = column_index * matrix_stride_usize;
_ = try column.write(input[@min(offset, input.len)..]);
} }
} }
return matrix_size; return matrix_size;
@@ -673,7 +703,7 @@ pub const Value = union(Type) {
.Array => |*arr| blk: { .Array => |*arr| blk: {
var offset: usize = 0; var offset: usize = 0;
for (arr.values) |*value| { for (arr.values) |*value| {
_ = try value.writeWithMatrixLayout(input[offset..], matrix_stride, row_major); _ = try value.writeWithMatrixLayout(input[@min(offset, input.len)..], matrix_stride, row_major);
offset += if (arr.stride != 0) arr.stride else try value.getPlainMemorySize(); offset += if (arr.stride != 0) arr.stride else try value.getPlainMemorySize();
} }
break :blk offset; break :blk offset;
@@ -688,10 +718,12 @@ pub const Value = union(Type) {
const info = @typeInfo(T).vector; const info = @typeInfo(T).vector;
const Lane = info.child; const Lane = info.child;
const size = info.len * @sizeOf(Lane); const size = info.len * @sizeOf(Lane);
if (in.len < size) return RuntimeError.OutOfBounds;
inline for (0..info.len) |i| { inline for (0..info.len) |i| {
const offset = i * @sizeOf(Lane); const offset = i * @sizeOf(Lane);
vec[i] = std.mem.bytesToValue(Lane, in[offset..][0..@sizeOf(Lane)]); vec[i] = if (offset + @sizeOf(Lane) <= in.len)
std.mem.bytesToValue(Lane, in[offset..][0..@sizeOf(Lane)])
else
0;
} }
return size; return size;
} }
@@ -699,27 +731,25 @@ pub const Value = union(Type) {
switch (self.*) { switch (self.*) {
.Bool => |*b| { .Bool => |*b| {
if (input.len < 1) return RuntimeError.OutOfBounds; b.* = if (input.len >= 1 and 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 => { 8 => {
if (input.len < 1) return RuntimeError.OutOfBounds; i.value.uint8 = if (input.len >= 1) @bitCast(input[0]) else 0;
i.value.uint8 = @bitCast(input[0]);
}, },
16 => { 16 => {
if (input.len < 2) return RuntimeError.OutOfBounds; i.value.uint16 = 0;
@memcpy(std.mem.asBytes(&i.value.uint16), input[0..2]); if (input.len >= 2) @memcpy(std.mem.asBytes(&i.value.uint16), input[0..2]);
}, },
32 => { 32 => {
if (input.len < 4) return RuntimeError.OutOfBounds; i.value.uint32 = 0;
@memcpy(std.mem.asBytes(&i.value.uint32), input[0..4]); if (input.len >= 4) @memcpy(std.mem.asBytes(&i.value.uint32), input[0..4]);
}, },
64 => { 64 => {
if (input.len < 8) return RuntimeError.OutOfBounds; i.value.uint64 = 0;
@memcpy(std.mem.asBytes(&i.value.uint64), input[0..8]); if (input.len >= 8) @memcpy(std.mem.asBytes(&i.value.uint64), input[0..8]);
}, },
else => return RuntimeError.InvalidValueType, else => return RuntimeError.InvalidValueType,
} }
@@ -728,16 +758,16 @@ pub const Value = union(Type) {
.Float => |*f| { .Float => |*f| {
switch (f.bit_count) { switch (f.bit_count) {
16 => { 16 => {
if (input.len < 2) return RuntimeError.OutOfBounds; f.value.float16 = 0;
@memcpy(std.mem.asBytes(&f.value.float16), input[0..2]); if (input.len >= 2) @memcpy(std.mem.asBytes(&f.value.float16), input[0..2]);
}, },
32 => { 32 => {
if (input.len < 4) return RuntimeError.OutOfBounds; f.value.float32 = 0;
@memcpy(std.mem.asBytes(&f.value.float32), input[0..4]); if (input.len >= 4) @memcpy(std.mem.asBytes(&f.value.float32), input[0..4]);
}, },
64 => { 64 => {
if (input.len < 8) return RuntimeError.OutOfBounds; f.value.float64 = 0;
@memcpy(std.mem.asBytes(&f.value.float64), input[0..8]); if (input.len >= 8) @memcpy(std.mem.asBytes(&f.value.float64), input[0..8]);
}, },
else => return RuntimeError.InvalidValueType, else => return RuntimeError.InvalidValueType,
} }
@@ -773,7 +803,12 @@ pub const Value = union(Type) {
.Array => |*arr| { .Array => |*arr| {
var offset: usize = 0; var offset: usize = 0;
for (arr.values) |*v| { for (arr.values) |*v| {
_ = try v.write(input[offset..]); if (v.* == .RuntimeArray) {
v.RuntimeArray.data = @constCast(input[@min(offset, input.len)..]);
offset += input.len - @min(offset, input.len);
continue;
}
_ = try v.write(input[@min(offset, input.len)..]);
offset += if (arr.stride != 0) arr.stride else try v.getPlainMemorySize(); offset += if (arr.stride != 0) arr.stride else try v.getPlainMemorySize();
} }
return offset; return offset;
@@ -782,20 +817,29 @@ 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; if (member_offset > input.len) {
if (v.* == .RuntimeArray) {
v.RuntimeArray.data = &.{};
continue;
}
}
const member_input = if (v.* == .RuntimeArray and i + 1 < s.values.len and s.offsets[i + 1] != null) blk: { const member_input = if (v.* == .RuntimeArray and i + 1 < s.values.len and s.offsets[i + 1] != null) blk: {
const next_offset: usize = @intCast(s.offsets[i + 1].?); const next_offset: usize = @intCast(s.offsets[i + 1].?);
if (next_offset < member_offset or next_offset > input.len) return RuntimeError.OutOfBounds; if (next_offset < member_offset) return RuntimeError.OutOfBounds;
break :blk input[member_offset..next_offset]; break :blk input[member_offset..@min(next_offset, input.len)];
} else input[member_offset..]; } else input[@min(member_offset, input.len)..];
if (v.* == .RuntimeArray) {
v.RuntimeArray.data = @constCast(member_input);
end_offset = @max(end_offset, input.len);
continue;
}
const write_size = if (s.matrix_strides[i]) |matrix_stride| const write_size = if (s.matrix_strides[i]) |matrix_stride|
try v.writeWithMatrixLayout(member_input, matrix_stride, s.row_major[i]) try v.writeWithMatrixLayout(member_input, matrix_stride, s.row_major[i])
else else
try v.write(member_input); try v.write(member_input);
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..@min(end_offset, input.len)]);
s.external_data = @constCast(input[0..end_offset]);
return end_offset; return end_offset;
}, },
.RuntimeArray => |*arr| { .RuntimeArray => |*arr| {
+239 -141
View File
@@ -1367,7 +1367,7 @@ fn ImageEngine(comptime Op: ImageOp) type {
}; };
} }
fn readProjectedSampleCoords(coordinate: *const Value) RuntimeError!struct { x: f32, y: f32, z: f32 } { fn readProjectedSampleCoords(coordinate: *const Value) RuntimeError!struct { x: f32, y: f32, z: f32, w: f32 } {
const lane_count = try valueLaneCount(coordinate); const lane_count = try valueLaneCount(coordinate);
if (lane_count < 2) if (lane_count < 2)
return RuntimeError.InvalidSpirV; return RuntimeError.InvalidSpirV;
@@ -1378,6 +1378,7 @@ fn ImageEngine(comptime Op: ImageOp) type {
.x = try readSampleCoordLane(coordinate, 0) / q, .x = try readSampleCoordLane(coordinate, 0) / q,
.y = if (q_lane > 1) (readSampleCoordLane(coordinate, 1) catch 0.0) / q else 0.0, .y = if (q_lane > 1) (readSampleCoordLane(coordinate, 1) catch 0.0) / q else 0.0,
.z = if (q_lane > 2) (readSampleCoordLane(coordinate, 2) catch 0.0) / q else 0.0, .z = if (q_lane > 2) (readSampleCoordLane(coordinate, 2) catch 0.0) / q else 0.0,
.w = if (q_lane > 3) (readSampleCoordLane(coordinate, 3) catch 0.0) / q else 0.0,
}; };
} }
@@ -1856,8 +1857,8 @@ fn ImageEngine(comptime Op: ImageOp) type {
return parsed.lod; return parsed.lod;
} }
fn sampleImageDref(rt: *Runtime, dst: *Value, driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, dref: f32, lod: ?f32, offset: Runtime.ImageOffset) RuntimeError!void { fn sampleImageDref(rt: *Runtime, dst: *Value, driver_image: *anyopaque, driver_sampler: *anyopaque, dim: spv.SpvDim, x: f32, y: f32, z: f32, w: f32, dref: f32, lod: ?f32, offset: Runtime.ImageOffset) RuntimeError!void {
try writeFloatScalar(dst, try rt.image_api.sampleImageDref(driver_image, driver_sampler, dim, x, y, z, dref, lod, offset)); try writeFloatScalar(dst, try rt.image_api.sampleImageDref(driver_image, driver_sampler, dim, x, y, z, w, dref, lod, offset));
} }
fn gatherCoord(index: i32, extent: u32) f32 { fn gatherCoord(index: i32, extent: u32) f32 {
@@ -2169,6 +2170,7 @@ fn ImageEngine(comptime Op: ImageOp) type {
.x = try readSampleCoordLane(coordinate, 0), .x = try readSampleCoordLane(coordinate, 0),
.y = readSampleCoordLane(coordinate, 1) catch 0, .y = readSampleCoordLane(coordinate, 1) catch 0,
.z = readSampleCoordLane(coordinate, 2) catch 0, .z = readSampleCoordLane(coordinate, 2) catch 0,
.w = readSampleCoordLane(coordinate, 3) catch 0,
}; };
const image_operands = if (word_count > 4) try rt.it.next() else 0; const image_operands = if (word_count > 4) try rt.it.next() else 0;
const parsed_operands = try parseImageOperands(rt, image_operands); const parsed_operands = try parseImageOperands(rt, image_operands);
@@ -2230,6 +2232,7 @@ fn ImageEngine(comptime Op: ImageOp) type {
.x = try readSampleCoordLane(coordinate, 0), .x = try readSampleCoordLane(coordinate, 0),
.y = readSampleCoordLane(coordinate, 1) catch 0, .y = readSampleCoordLane(coordinate, 1) catch 0,
.z = readSampleCoordLane(coordinate, 2) catch 0, .z = readSampleCoordLane(coordinate, 2) catch 0,
.w = readSampleCoordLane(coordinate, 3) catch 0,
}; };
const raw_dref = try readFloatLane(try rt.results[try rt.it.next()].getValue(), 0); const raw_dref = try readFloatLane(try rt.results[try rt.it.next()].getValue(), 0);
const dref = if (comptime Op == .SampleProjDrefImplicitLod) const dref = if (comptime Op == .SampleProjDrefImplicitLod)
@@ -2238,6 +2241,20 @@ fn ImageEngine(comptime Op: ImageOp) type {
raw_dref; raw_dref;
const image_operands = if (word_count > 5) try rt.it.next() else 0; const image_operands = if (word_count > 5) try rt.it.next() else 0;
const parsed_operands = try parseImageOperands(rt, image_operands); const parsed_operands = try parseImageOperands(rt, image_operands);
const projected = comptime Op == .SampleProjDrefImplicitLod;
const lod = try implicitSampleLod(
rt,
coordinate_id,
coordinate,
projected,
sampled_image_operand.driver_image,
sampled_image_operand.driver_sampler,
sampled_image_operand.dim,
coords.x,
coords.y,
coords.z,
parsed_operands.bias,
);
try sampleImageDref( try sampleImageDref(
rt, rt,
@@ -2248,8 +2265,9 @@ fn ImageEngine(comptime Op: ImageOp) type {
coords.x, coords.x,
coords.y, coords.y,
coords.z, coords.z,
coords.w,
dref, dref,
null, lod,
parsed_operands.offset, parsed_operands.offset,
); );
}, },
@@ -2265,6 +2283,7 @@ fn ImageEngine(comptime Op: ImageOp) type {
.x = try readSampleCoordLane(coordinate, 0), .x = try readSampleCoordLane(coordinate, 0),
.y = readSampleCoordLane(coordinate, 1) catch 0, .y = readSampleCoordLane(coordinate, 1) catch 0,
.z = readSampleCoordLane(coordinate, 2) catch 0, .z = readSampleCoordLane(coordinate, 2) catch 0,
.w = readSampleCoordLane(coordinate, 3) catch 0,
}; };
const image_operands = if (word_count > 4) try rt.it.next() else 0; const image_operands = if (word_count > 4) try rt.it.next() else 0;
const parsed_operands = try parseImageOperands(rt, image_operands); const parsed_operands = try parseImageOperands(rt, image_operands);
@@ -2300,6 +2319,7 @@ fn ImageEngine(comptime Op: ImageOp) type {
.x = try readSampleCoordLane(coordinate, 0), .x = try readSampleCoordLane(coordinate, 0),
.y = readSampleCoordLane(coordinate, 1) catch 0, .y = readSampleCoordLane(coordinate, 1) catch 0,
.z = readSampleCoordLane(coordinate, 2) catch 0, .z = readSampleCoordLane(coordinate, 2) catch 0,
.w = readSampleCoordLane(coordinate, 3) catch 0,
}; };
const raw_dref = try readFloatLane(try rt.results[try rt.it.next()].getValue(), 0); const raw_dref = try readFloatLane(try rt.results[try rt.it.next()].getValue(), 0);
const dref = if (comptime Op == .SampleProjDrefExplicitLod) const dref = if (comptime Op == .SampleProjDrefExplicitLod)
@@ -2318,6 +2338,7 @@ fn ImageEngine(comptime Op: ImageOp) type {
coords.x, coords.x,
coords.y, coords.y,
coords.z, coords.z,
coords.w,
dref, dref,
try explicitSampleLod( try explicitSampleLod(
rt, rt,
@@ -3514,9 +3535,60 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
.indexes = indexes, .indexes = indexes,
.value = blk: { .value = blk: {
const helpers = struct { const helpers = struct {
const F32Pointer = struct {
ptr: *f32,
backing: ?*Value,
owns_backing: bool,
};
const I32Pointer = struct {
ptr: *i32,
backing: ?*Value,
owns_backing: bool,
};
const U32Pointer = struct {
ptr: *u32,
backing: ?*Value,
owns_backing: bool,
};
fn destroyBacking(gpa: std.mem.Allocator, backing: ?*Value, owns_backing: bool) void {
if (!owns_backing) return;
if (backing) |value| {
value.deinit(gpa);
gpa.destroy(value);
}
}
fn robustF32Pointer(gpa: std.mem.Allocator, ptr: ?*f32, window: ?[]u8, descriptor_backed: bool, backing: ?*Value, owns_backing: bool) RuntimeError!F32Pointer {
if (window != null or !descriptor_backed) return .{ .ptr = ptr orelse return RuntimeError.InvalidSpirV, .backing = backing, .owns_backing = owns_backing };
destroyBacking(gpa, backing, owns_backing);
const value = gpa.create(Value) catch return RuntimeError.OutOfMemory;
value.* = .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = 0 } } };
return .{ .ptr = &value.Float.value.float32, .backing = value, .owns_backing = true };
}
fn robustI32Pointer(gpa: std.mem.Allocator, ptr: ?*i32, window: ?[]u8, descriptor_backed: bool, backing: ?*Value, owns_backing: bool) RuntimeError!I32Pointer {
if (window != null or !descriptor_backed) return .{ .ptr = ptr orelse return RuntimeError.InvalidSpirV, .backing = backing, .owns_backing = owns_backing };
destroyBacking(gpa, backing, owns_backing);
const value = gpa.create(Value) catch return RuntimeError.OutOfMemory;
value.* = .{ .Int = .{ .bit_count = 32, .is_signed = true, .value = .{ .sint32 = 0 } } };
return .{ .ptr = &value.Int.value.sint32, .backing = value, .owns_backing = true };
}
fn robustU32Pointer(gpa: std.mem.Allocator, ptr: ?*u32, window: ?[]u8, descriptor_backed: bool, backing: ?*Value, owns_backing: bool) RuntimeError!U32Pointer {
if (window != null or !descriptor_backed) return .{ .ptr = ptr orelse return RuntimeError.InvalidSpirV, .backing = backing, .owns_backing = owns_backing };
destroyBacking(gpa, backing, owns_backing);
const value = gpa.create(Value) catch return RuntimeError.OutOfMemory;
value.* = .{ .Int = .{ .bit_count = 32, .is_signed = false, .value = .{ .uint32 = 0 } } };
return .{ .ptr = &value.Int.value.uint32, .backing = value, .owns_backing = true };
}
fn advanceWindow(window: ?[]u8, offset: usize) RuntimeError!?[]u8 { fn advanceWindow(window: ?[]u8, offset: usize) RuntimeError!?[]u8 {
if (window) |w| { if (window) |w| {
if (offset > w.len) return RuntimeError.OutOfBounds; if (offset > w.len) return null;
return w[offset..]; return w[offset..];
} }
return null; return null;
@@ -3524,7 +3596,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
fn advanceWindowSized(window: ?[]u8, offset: usize, size: usize) RuntimeError!?[]u8 { fn advanceWindowSized(window: ?[]u8, offset: usize, size: usize) RuntimeError!?[]u8 {
if (window) |w| { if (window) |w| {
if (offset > w.len or size > w.len - offset) return RuntimeError.OutOfBounds; if (offset > w.len or size > w.len - offset) return null;
return w[offset .. offset + size]; return w[offset .. offset + size];
} }
return null; return null;
@@ -3545,6 +3617,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
var owns_uniform_backing_value = false; var owns_uniform_backing_value = false;
var matrix_stride: ?SpvWord = null; var matrix_stride: ?SpvWord = null;
var matrix_row_major = false; var matrix_row_major = false;
var descriptor_backed = 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;
@@ -3553,6 +3626,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
owns_uniform_backing_value = false; owns_uniform_backing_value = false;
matrix_stride = ptr.matrix_stride; matrix_stride = ptr.matrix_stride;
matrix_row_major = ptr.matrix_row_major; matrix_row_major = ptr.matrix_row_major;
descriptor_backed = uniform_slice_window != null or uniform_backing_value != null;
switch (ptr.ptr) { switch (ptr.ptr) {
.common => |common| value_ptr = common, .common => |common| value_ptr = common,
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
@@ -3579,6 +3653,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
owns_uniform_backing_value = false; owns_uniform_backing_value = false;
matrix_stride = ptr.matrix_stride; matrix_stride = ptr.matrix_stride;
matrix_row_major = ptr.matrix_row_major; matrix_row_major = ptr.matrix_row_major;
descriptor_backed = uniform_slice_window != null or uniform_backing_value != null;
switch (ptr.ptr) { switch (ptr.ptr) {
.common => |common| value_ptr = common, .common => |common| value_ptr = common,
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
@@ -3639,8 +3714,10 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
const member_offset: usize = @intCast(s.offsets[component_index] orelse end_offset); const member_offset: usize = @intCast(s.offsets[component_index] orelse end_offset);
if (uniform_slice_window != null) { if (uniform_slice_window != null) {
descriptor_backed = true;
uniform_slice_window = try helpers.advanceWindow(uniform_slice_window, member_offset); uniform_slice_window = try helpers.advanceWindow(uniform_slice_window, member_offset);
} else if (s.external_data) |data| { } else if (s.external_data) |data| {
descriptor_backed = true;
uniform_slice_window = try helpers.advanceWindow(data, member_offset); uniform_slice_window = try helpers.advanceWindow(data, member_offset);
} }
@@ -3658,13 +3735,7 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
} }
}, },
.RuntimeArray => |*arr| { .RuntimeArray => |*arr| {
if (component_index >= arr.getLen()) return RuntimeError.OutOfBounds; const backing = try arr.createRobustValueFromIndex(allocator, rt.results, component_index);
const element_offset = arr.getOffsetOfIndex(component_index);
if (element_offset > arr.data.len or arr.stride > arr.data.len - element_offset)
return RuntimeError.OutOfBounds;
const backing = try arr.createValueFromIndex(allocator, rt.results, component_index);
errdefer { errdefer {
backing.deinit(allocator); backing.deinit(allocator);
allocator.destroy(backing); allocator.destroy(backing);
@@ -3678,7 +3749,11 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
value_ptr = backing; value_ptr = backing;
uniform_backing_value = backing; uniform_backing_value = backing;
owns_uniform_backing_value = true; owns_uniform_backing_value = true;
uniform_slice_window = arr.data[element_offset .. element_offset + arr.stride]; descriptor_backed = true;
uniform_slice_window = if (arr.getRobustOffsetOfIndex(component_index)) |element_offset|
arr.data[element_offset..]
else
null;
if (arr.matrix_stride) |stride| { if (arr.matrix_stride) |stride| {
matrix_stride = stride; matrix_stride = stride;
matrix_row_major = arr.row_major; matrix_row_major = arr.row_major;
@@ -3692,94 +3767,103 @@ fn opAccessChain(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime
} }
}, },
.Vector4f32 => |*v| switch (component_index) { .Vector4f32 => |*v| switch (component_index) {
inline 0...3 => |idx| break :blk .{ .Pointer = .{ inline 0...3 => |idx| {
.ptr = .{ .f32_ptr = &v[idx] }, const lane_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(f32)), @sizeOf(f32));
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(f32)), @sizeOf(f32)), const ptr = try helpers.robustF32Pointer(allocator, &v[idx], lane_window, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
.uniform_backing_value = uniform_backing_value, break :blk .{ .Pointer = .{ .ptr = .{ .f32_ptr = ptr.ptr }, .uniform_slice_window = lane_window, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
.owns_uniform_backing_value = owns_uniform_backing_value, },
.matrix_stride = null, else => {
} }, const ptr = try helpers.robustF32Pointer(allocator, null, null, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
else => return RuntimeError.InvalidSpirV, break :blk .{ .Pointer = .{ .ptr = .{ .f32_ptr = ptr.ptr }, .uniform_slice_window = null, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
},
}, },
.Vector3f32 => |*v| switch (component_index) { .Vector3f32 => |*v| switch (component_index) {
inline 0...2 => |idx| break :blk .{ .Pointer = .{ inline 0...2 => |idx| {
.ptr = .{ .f32_ptr = &v[idx] }, const lane_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(f32)), @sizeOf(f32));
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(f32)), @sizeOf(f32)), const ptr = try helpers.robustF32Pointer(allocator, &v[idx], lane_window, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
.uniform_backing_value = uniform_backing_value, break :blk .{ .Pointer = .{ .ptr = .{ .f32_ptr = ptr.ptr }, .uniform_slice_window = lane_window, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
.owns_uniform_backing_value = owns_uniform_backing_value, },
.matrix_stride = null, else => {
} }, const ptr = try helpers.robustF32Pointer(allocator, null, null, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
else => return RuntimeError.InvalidSpirV, break :blk .{ .Pointer = .{ .ptr = .{ .f32_ptr = ptr.ptr }, .uniform_slice_window = null, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
},
}, },
.Vector2f32 => |*v| switch (component_index) { .Vector2f32 => |*v| switch (component_index) {
inline 0...1 => |idx| break :blk .{ .Pointer = .{ inline 0...1 => |idx| {
.ptr = .{ .f32_ptr = &v[idx] }, const lane_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(f32)), @sizeOf(f32));
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(f32)), @sizeOf(f32)), const ptr = try helpers.robustF32Pointer(allocator, &v[idx], lane_window, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
.uniform_backing_value = uniform_backing_value, break :blk .{ .Pointer = .{ .ptr = .{ .f32_ptr = ptr.ptr }, .uniform_slice_window = lane_window, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
.owns_uniform_backing_value = owns_uniform_backing_value, },
.matrix_stride = null, else => {
} }, const ptr = try helpers.robustF32Pointer(allocator, null, null, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
else => return RuntimeError.InvalidSpirV, break :blk .{ .Pointer = .{ .ptr = .{ .f32_ptr = ptr.ptr }, .uniform_slice_window = null, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
},
}, },
.Vector4i32 => |*v| switch (component_index) { .Vector4i32 => |*v| switch (component_index) {
inline 0...3 => |idx| break :blk .{ .Pointer = .{ inline 0...3 => |idx| {
.ptr = .{ .i32_ptr = &v[idx] }, const lane_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(i32)), @sizeOf(i32));
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(i32)), @sizeOf(i32)), const ptr = try helpers.robustI32Pointer(allocator, &v[idx], lane_window, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
.uniform_backing_value = uniform_backing_value, break :blk .{ .Pointer = .{ .ptr = .{ .i32_ptr = ptr.ptr }, .uniform_slice_window = lane_window, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
.owns_uniform_backing_value = owns_uniform_backing_value, },
.matrix_stride = null, else => {
} }, const ptr = try helpers.robustI32Pointer(allocator, null, null, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
else => return RuntimeError.InvalidSpirV, break :blk .{ .Pointer = .{ .ptr = .{ .i32_ptr = ptr.ptr }, .uniform_slice_window = null, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
},
}, },
.Vector3i32 => |*v| switch (component_index) { .Vector3i32 => |*v| switch (component_index) {
inline 0...2 => |idx| break :blk .{ .Pointer = .{ inline 0...2 => |idx| {
.ptr = .{ .i32_ptr = &v[idx] }, const lane_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(i32)), @sizeOf(i32));
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(i32)), @sizeOf(i32)), const ptr = try helpers.robustI32Pointer(allocator, &v[idx], lane_window, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
.uniform_backing_value = uniform_backing_value, break :blk .{ .Pointer = .{ .ptr = .{ .i32_ptr = ptr.ptr }, .uniform_slice_window = lane_window, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
.owns_uniform_backing_value = owns_uniform_backing_value, },
.matrix_stride = null, else => {
} }, const ptr = try helpers.robustI32Pointer(allocator, null, null, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
else => return RuntimeError.InvalidSpirV, break :blk .{ .Pointer = .{ .ptr = .{ .i32_ptr = ptr.ptr }, .uniform_slice_window = null, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
},
}, },
.Vector2i32 => |*v| switch (component_index) { .Vector2i32 => |*v| switch (component_index) {
inline 0...1 => |idx| break :blk .{ .Pointer = .{ inline 0...1 => |idx| {
.ptr = .{ .i32_ptr = &v[idx] }, const lane_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(i32)), @sizeOf(i32));
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(i32)), @sizeOf(i32)), const ptr = try helpers.robustI32Pointer(allocator, &v[idx], lane_window, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
.uniform_backing_value = uniform_backing_value, break :blk .{ .Pointer = .{ .ptr = .{ .i32_ptr = ptr.ptr }, .uniform_slice_window = lane_window, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
.owns_uniform_backing_value = owns_uniform_backing_value, },
.matrix_stride = null, else => {
} }, const ptr = try helpers.robustI32Pointer(allocator, null, null, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
else => return RuntimeError.InvalidSpirV, break :blk .{ .Pointer = .{ .ptr = .{ .i32_ptr = ptr.ptr }, .uniform_slice_window = null, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
},
}, },
.Vector4u32 => |*v| switch (component_index) { .Vector4u32 => |*v| switch (component_index) {
inline 0...3 => |idx| break :blk .{ .Pointer = .{ inline 0...3 => |idx| {
.ptr = .{ .u32_ptr = &v[idx] }, const lane_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(u32)), @sizeOf(u32));
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(u32)), @sizeOf(u32)), const ptr = try helpers.robustU32Pointer(allocator, &v[idx], lane_window, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
.uniform_backing_value = uniform_backing_value, break :blk .{ .Pointer = .{ .ptr = .{ .u32_ptr = ptr.ptr }, .uniform_slice_window = lane_window, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
.owns_uniform_backing_value = owns_uniform_backing_value, },
.matrix_stride = null, else => {
} }, const ptr = try helpers.robustU32Pointer(allocator, null, null, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
else => return RuntimeError.InvalidSpirV, break :blk .{ .Pointer = .{ .ptr = .{ .u32_ptr = ptr.ptr }, .uniform_slice_window = null, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
},
}, },
.Vector3u32 => |*v| switch (component_index) { .Vector3u32 => |*v| switch (component_index) {
inline 0...2 => |idx| break :blk .{ .Pointer = .{ inline 0...2 => |idx| {
.ptr = .{ .u32_ptr = &v[idx] }, const lane_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(u32)), @sizeOf(u32));
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(u32)), @sizeOf(u32)), const ptr = try helpers.robustU32Pointer(allocator, &v[idx], lane_window, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
.uniform_backing_value = uniform_backing_value, break :blk .{ .Pointer = .{ .ptr = .{ .u32_ptr = ptr.ptr }, .uniform_slice_window = lane_window, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
.owns_uniform_backing_value = owns_uniform_backing_value, },
.matrix_stride = null, else => {
} }, const ptr = try helpers.robustU32Pointer(allocator, null, null, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
else => return RuntimeError.InvalidSpirV, break :blk .{ .Pointer = .{ .ptr = .{ .u32_ptr = ptr.ptr }, .uniform_slice_window = null, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
},
}, },
.Vector2u32 => |*v| switch (component_index) { .Vector2u32 => |*v| switch (component_index) {
inline 0...1 => |idx| break :blk .{ .Pointer = .{ inline 0...1 => |idx| {
.ptr = .{ .u32_ptr = &v[idx] }, const lane_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(u32)), @sizeOf(u32));
.uniform_slice_window = try helpers.advanceWindowSized(uniform_slice_window, helpers.laneOffset(matrix_stride, matrix_row_major, idx, @sizeOf(u32)), @sizeOf(u32)), const ptr = try helpers.robustU32Pointer(allocator, &v[idx], lane_window, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
.uniform_backing_value = uniform_backing_value, break :blk .{ .Pointer = .{ .ptr = .{ .u32_ptr = ptr.ptr }, .uniform_slice_window = lane_window, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
.owns_uniform_backing_value = owns_uniform_backing_value, },
.matrix_stride = null, else => {
} }, const ptr = try helpers.robustU32Pointer(allocator, null, null, descriptor_backed, uniform_backing_value, owns_uniform_backing_value);
else => return RuntimeError.InvalidSpirV, break :blk .{ .Pointer = .{ .ptr = .{ .u32_ptr = ptr.ptr }, .uniform_slice_window = null, .uniform_backing_value = ptr.backing, .owns_uniform_backing_value = ptr.owns_backing, .matrix_stride = null } };
},
}, },
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
} }
@@ -4017,17 +4101,71 @@ fn opCompositeConstruct(allocator: std.mem.Allocator, word_count: SpvWord, rt: *
} }
} }
fn extractCompositeValue(allocator: std.mem.Allocator, results: []Result, value: *const Value, member_ids: []const SpvWord) RuntimeError!Value {
var composite = value.*;
for (member_ids) |member_id_word| {
const member_id: usize = @intCast(member_id_word);
if (composite.getCompositeDataOrNull()) |v| {
composite = v[member_id];
continue;
}
switch (composite) {
.RuntimeArray => |arr| composite = try arr.createLocalValueFromIndex(allocator, results, member_id_word),
.Vector4f32 => |v| return .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = switch (member_id) {
inline 0...3 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector3f32 => |v| return .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = switch (member_id) {
inline 0...2 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector2f32 => |v| return .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = switch (member_id) {
inline 0...1 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector4i32 => |v| return .{ .Int = .{ .bit_count = 32, .is_signed = true, .value = .{ .sint32 = switch (member_id) {
inline 0...3 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector3i32 => |v| return .{ .Int = .{ .bit_count = 32, .is_signed = true, .value = .{ .sint32 = switch (member_id) {
inline 0...2 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector2i32 => |v| return .{ .Int = .{ .bit_count = 32, .is_signed = true, .value = .{ .sint32 = switch (member_id) {
inline 0...1 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector4u32 => |v| return .{ .Int = .{ .bit_count = 32, .is_signed = false, .value = .{ .uint32 = switch (member_id) {
inline 0...3 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector3u32 => |v| return .{ .Int = .{ .bit_count = 32, .is_signed = false, .value = .{ .uint32 = switch (member_id) {
inline 0...2 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector2u32 => |v| return .{ .Int = .{ .bit_count = 32, .is_signed = false, .value = .{ .uint32 = switch (member_id) {
inline 0...1 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
else => return RuntimeError.InvalidValueType,
}
}
return composite.dupe(allocator);
}
fn opCompositeExtract(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void { fn opCompositeExtract(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {
const res_type = try rt.it.next(); const res_type = try rt.it.next();
const id = try rt.it.next(); const id = try rt.it.next();
const composite_id = try rt.it.next(); const composite_id = try rt.it.next();
const index_count: usize = @intCast(word_count - 3); const index_count: usize = @intCast(word_count - 3);
var arena = std.heap.ArenaAllocator.init(allocator); const member_ids = allocator.alloc(SpvWord, index_count) catch return RuntimeError.OutOfMemory;
defer arena.deinit(); defer allocator.free(member_ids);
for (member_ids) |*member_id| {
const arena_allocator = arena.allocator(); member_id.* = try rt.it.next();
}
const value = try extractCompositeValue(allocator, rt.results, try rt.results[composite_id].getValue(), member_ids);
rt.results[id].variant = .{ rt.results[id].variant = .{
.Constant = .{ .Constant = .{
.type_word = res_type, .type_word = res_type,
@@ -4035,59 +4173,19 @@ fn opCompositeExtract(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Ru
.Type => |t| @as(Result.Type, t), .Type => |t| @as(Result.Type, t),
else => return RuntimeError.InvalidSpirV, else => return RuntimeError.InvalidSpirV,
}, },
.value = blk: { .value = value,
var composite = (try rt.results[composite_id].getValue()).*;
for (0..index_count) |_| {
const member_id = try rt.it.next();
if (composite.getCompositeDataOrNull()) |v| {
composite = v[member_id];
continue;
}
switch (composite) {
.RuntimeArray => |arr| composite = try arr.createLocalValueFromIndex(arena_allocator, rt.results, member_id),
.Vector4f32 => |v| break :blk .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = switch (member_id) {
inline 0...3 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector3f32 => |v| break :blk .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = switch (member_id) {
inline 0...2 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector2f32 => |v| break :blk .{ .Float = .{ .bit_count = 32, .value = .{ .float32 = switch (member_id) {
inline 0...1 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector4i32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .is_signed = true, .value = .{ .sint32 = switch (member_id) {
inline 0...3 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector3i32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .is_signed = true, .value = .{ .sint32 = switch (member_id) {
inline 0...2 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector2i32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .is_signed = true, .value = .{ .sint32 = switch (member_id) {
inline 0...1 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector4u32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .is_signed = false, .value = .{ .uint32 = switch (member_id) {
inline 0...3 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector3u32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .is_signed = false, .value = .{ .uint32 = switch (member_id) {
inline 0...2 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
.Vector2u32 => |v| break :blk .{ .Int = .{ .bit_count = 32, .is_signed = false, .value = .{ .uint32 = switch (member_id) {
inline 0...1 => |idx| v[idx],
else => return RuntimeError.OutOfBounds,
} } } },
else => return RuntimeError.InvalidValueType,
}
}
break :blk try composite.dupe(allocator);
},
}, },
}; };
if (rt.derivatives.get(composite_id)) |derivative| {
var dx = try extractCompositeValue(allocator, rt.results, &derivative.dx, member_ids);
defer dx.deinit(allocator);
var dy = try extractCompositeValue(allocator, rt.results, &derivative.dy, member_ids);
defer dy.deinit(allocator);
try rt.setDerivative(allocator, id, &dx, &dy);
} else {
rt.clearDerivative(allocator, id);
}
} }
fn opCompositeInsert(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void { fn opCompositeInsert(allocator: std.mem.Allocator, word_count: SpvWord, rt: *Runtime) RuntimeError!void {